6 * Mach Operating System
7 * Copyright (c) 1991,1990 Carnegie Mellon University
10 * Permission to use, copy, modify and distribute this software and its
11 * documentation is hereby granted, provided that both the copyright
12 * notice and this permission notice appear in all copies of the
13 * software, derivative works or modified versions, and any portions
14 * thereof, and that both notices appear in supporting documentation.
16 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
17 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
18 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
20 * Carnegie Mellon requests users of this software to return to
22 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
23 * School of Computer Science
24 * Carnegie Mellon University
25 * Pittsburgh PA 15213-3890
27 * any improvements or extensions that they make and grant Carnegie Mellon
28 * the rights to redistribute these changes.
32 #include <mach/mach.h>
33 #include <mach/boolean.h>
34 #include <mach/kern_return.h>
35 #include <mach/message.h>
36 #include <mach/mig_errors.h>
37 #include <mach/vm_statistics.h>
40 * Routine: mach_msg_server_once
42 * A simple generic server function. It allows more flexibility
43 * than mach_msg_server by processing only one message request
44 * and then returning to the user. Note that more in the way
45 * of error codes are returned to the user; specifically, any
46 * failing error from mach_msg_overwrite_trap will be returned
47 * (though errors from the demux routine or the routine it calls
52 boolean_t (*demux
)(mach_msg_header_t
*, mach_msg_header_t
*),
53 mach_msg_size_t max_size
,
55 mach_msg_options_t options
)
57 mig_reply_error_t
*bufRequest
= 0, *bufReply
= 0, *bufTemp
;
58 register mach_msg_return_t mr
;
59 register kern_return_t kr
;
61 if ((kr
= vm_allocate(mach_task_self(),
62 (vm_address_t
*)&bufRequest
,
63 max_size
+ MAX_TRAILER_SIZE
,
64 VM_MAKE_TAG(VM_MEMORY_MACH_MSG
)|TRUE
)) != KERN_SUCCESS
)
66 if ((kr
= vm_allocate(mach_task_self(),
67 (vm_address_t
*)&bufReply
,
68 max_size
+ MAX_TRAILER_SIZE
,
69 VM_MAKE_TAG(VM_MEMORY_MACH_MSG
)|TRUE
)) != KERN_SUCCESS
)
72 mr
= mach_msg_overwrite_trap(&bufRequest
->Head
, MACH_RCV_MSG
|options
,
73 0, max_size
, rcv_name
,
74 MACH_MSG_TIMEOUT_NONE
, MACH_PORT_NULL
,
75 (mach_msg_header_t
*) 0, 0);
76 if (mr
== MACH_MSG_SUCCESS
) {
77 /* we have a request message */
79 (void) (*demux
)(&bufRequest
->Head
, &bufReply
->Head
);
81 if (!(bufReply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
) &&
82 bufReply
->RetCode
!= KERN_SUCCESS
) {
83 if (bufReply
->RetCode
== MIG_NO_REPLY
)
85 * This return code is a little tricky--
86 * it appears that the demux routine found an
87 * error of some sort, but since that error
88 * would not normally get returned either to
89 * the local user or the remote one, we pretend it's
94 /* don't destroy the reply port right,
95 so we can send an error message */
96 bufRequest
->Head
.msgh_remote_port
= MACH_PORT_NULL
;
97 mach_msg_destroy(&bufRequest
->Head
);
100 if (bufReply
->Head
.msgh_remote_port
== MACH_PORT_NULL
) {
101 /* no reply port, so destroy the reply */
102 if (bufReply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
)
103 mach_msg_destroy(&bufReply
->Head
);
110 bufTemp
= bufRequest
;
111 bufRequest
= bufReply
;
115 * We don't want to block indefinitely because the client
116 * isn't receiving messages from the reply port.
117 * If we have a send-once right for the reply port, then
118 * this isn't a concern because the send won't block.
119 * If we have a send right, we need to use MACH_SEND_TIMEOUT.
120 * To avoid falling off the kernel's fast RPC path unnecessarily,
121 * we only supply MACH_SEND_TIMEOUT when absolutely necessary.
124 mr
= mach_msg_overwrite_trap(&bufRequest
->Head
,
125 (MACH_MSGH_BITS_REMOTE(bufRequest
->Head
.msgh_bits
) ==
126 MACH_MSG_TYPE_MOVE_SEND_ONCE
) ?
127 MACH_SEND_MSG
|options
:
128 MACH_SEND_MSG
|MACH_SEND_TIMEOUT
|options
,
129 bufRequest
->Head
.msgh_size
, 0, MACH_PORT_NULL
,
130 0, MACH_PORT_NULL
, (mach_msg_header_t
*) 0, 0);
132 /* Has a message error occurred? */
135 case MACH_SEND_INVALID_DEST
:
136 case MACH_SEND_TIMED_OUT
:
137 /* the reply can't be delivered, so destroy it */
138 mach_msg_destroy(&bufRequest
->Head
);
139 return KERN_SUCCESS
; /* Matches error hiding behavior in
142 case MACH_RCV_TOO_LARGE
:
143 return KERN_SUCCESS
; /* Matches error hiding behavior in
147 /* Includes success case. */
148 (void)vm_deallocate(mach_task_self(),
149 (vm_address_t
) bufRequest
,
150 max_size
+ MAX_TRAILER_SIZE
);
151 (void)vm_deallocate(mach_task_self(),
152 (vm_address_t
) bufReply
,
153 max_size
+ MAX_TRAILER_SIZE
);
159 * Routine: mach_msg_server
161 * A simple generic server function. Note that changes here
162 * should be considered for duplication above.
166 boolean_t (*demux
)(mach_msg_header_t
*, mach_msg_header_t
*),
167 mach_msg_size_t max_size
,
168 mach_port_t rcv_name
,
169 mach_msg_options_t options
)
171 mig_reply_error_t
*bufRequest
= 0, *bufReply
= 0, *bufTemp
;
172 register mach_msg_return_t mr
;
173 register kern_return_t kr
;
175 if ((kr
= vm_allocate(mach_task_self(),
176 (vm_address_t
*)&bufRequest
,
177 max_size
+ MAX_TRAILER_SIZE
,
178 VM_MAKE_TAG(VM_MEMORY_MACH_MSG
)|TRUE
)) != KERN_SUCCESS
)
180 if ((kr
= vm_allocate(mach_task_self(),
181 (vm_address_t
*)&bufReply
,
182 max_size
+ MAX_TRAILER_SIZE
,
183 VM_MAKE_TAG(VM_MEMORY_MACH_MSG
)|TRUE
)) != KERN_SUCCESS
)
188 mr
= mach_msg_overwrite_trap(&bufRequest
->Head
, MACH_RCV_MSG
|options
,
189 0, max_size
, rcv_name
,
190 MACH_MSG_TIMEOUT_NONE
, MACH_PORT_NULL
,
191 (mach_msg_header_t
*) 0, 0);
192 while (mr
== MACH_MSG_SUCCESS
) {
193 /* we have a request message */
195 (void) (*demux
)(&bufRequest
->Head
, &bufReply
->Head
);
197 if (!(bufReply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
) &&
198 bufReply
->RetCode
!= KERN_SUCCESS
) {
199 if (bufReply
->RetCode
== MIG_NO_REPLY
)
202 /* don't destroy the reply port right,
203 so we can send an error message */
204 bufRequest
->Head
.msgh_remote_port
= MACH_PORT_NULL
;
205 mach_msg_destroy(&bufRequest
->Head
);
208 if (bufReply
->Head
.msgh_remote_port
== MACH_PORT_NULL
) {
209 /* no reply port, so destroy the reply */
210 if (bufReply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
)
211 mach_msg_destroy(&bufReply
->Head
);
216 /* send reply and get next request */
218 bufTemp
= bufRequest
;
219 bufRequest
= bufReply
;
223 * We don't want to block indefinitely because the client
224 * isn't receiving messages from the reply port.
225 * If we have a send-once right for the reply port, then
226 * this isn't a concern because the send won't block.
227 * If we have a send right, we need to use MACH_SEND_TIMEOUT.
228 * To avoid falling off the kernel's fast RPC path unnecessarily,
229 * we only supply MACH_SEND_TIMEOUT when absolutely necessary.
232 mr
= mach_msg_overwrite_trap(&bufRequest
->Head
,
233 (MACH_MSGH_BITS_REMOTE(bufRequest
->Head
.msgh_bits
) ==
234 MACH_MSG_TYPE_MOVE_SEND_ONCE
) ?
235 MACH_SEND_MSG
|MACH_RCV_MSG
|options
:
236 MACH_SEND_MSG
|MACH_SEND_TIMEOUT
|MACH_RCV_MSG
|options
,
237 bufRequest
->Head
.msgh_size
, max_size
, rcv_name
,
238 0, MACH_PORT_NULL
, (mach_msg_header_t
*) 0, 0);
241 /* a message error occurred */
244 case MACH_SEND_INVALID_DEST
:
245 case MACH_SEND_TIMED_OUT
:
246 /* the reply can't be delivered, so destroy it */
247 mach_msg_destroy(&bufRequest
->Head
);
250 case MACH_RCV_TOO_LARGE
:
251 /* the kernel destroyed the request */
255 /* should only happen if the server is buggy */
256 (void)vm_deallocate(mach_task_self(),
257 (vm_address_t
) bufRequest
,
258 max_size
+ MAX_TRAILER_SIZE
);
259 (void)vm_deallocate(mach_task_self(),
260 (vm_address_t
) bufReply
,
261 max_size
+ MAX_TRAILER_SIZE
);