1 /* Copyright (C) 1993-2022 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3 
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8 
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.  */
17 
18 /* Based on CMU's mach_msg_server.c revision 2.4 of 91/05/14, and thus
19    under the following copyright.  Rewritten by Roland McGrath (FSF)
20    93/12/06 to use stack space instead of malloc, and to handle
21    large messages with MACH_RCV_LARGE.  */
22 
23 /*
24  * Mach Operating System
25  * Copyright (c) 1991,1990 Carnegie Mellon University
26  * All Rights Reserved.
27  *
28  * Permission to use, copy, modify and distribute this software and its
29  * documentation is hereby granted, provided that both the copyright
30  * notice and this permission notice appear in all copies of the
31  * software, derivative works or modified versions, and any portions
32  * thereof, and that both notices appear in supporting documentation.
33  *
34  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
35  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
36  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
37  *
38  * Carnegie Mellon requests users of this software to return to
39  *
40  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
41  *  School of Computer Science
42  *  Carnegie Mellon University
43  *  Pittsburgh PA 15213-3890
44  *
45  * any improvements or extensions that they make and grant Carnegie Mellon
46  * the rights to redistribute these changes.
47  */
48 /*
49  * (pre-GNU) HISTORY
50  *
51  * Revision 2.4  91/05/14  17:53:22  mrt
52  * 	Correcting copyright
53  *
54  * Revision 2.3  91/02/14  14:17:47  mrt
55  * 	Added new Mach copyright
56  * 	[91/02/13  12:44:20  mrt]
57  *
58  * Revision 2.2  90/08/06  17:23:58  rpd
59  * 	Created.
60  *
61  */
62 
63 
64 #include <mach.h>
65 #include <mach/mig_errors.h>
66 #include <stdlib.h>		/* For malloc and free.  */
67 #include <assert.h>
68 
69 #ifdef NDR_CHAR_ASCII		/* OSF Mach flavors have different names.  */
70 # define mig_reply_header_t	mig_reply_error_t
71 #endif
72 
73 mach_msg_return_t
__mach_msg_server_timeout(boolean_t (* demux)(mach_msg_header_t * request,mach_msg_header_t * reply),mach_msg_size_t max_size,mach_port_t rcv_name,mach_msg_option_t option,mach_msg_timeout_t timeout)74 __mach_msg_server_timeout (boolean_t (*demux) (mach_msg_header_t *request,
75 					       mach_msg_header_t *reply),
76 			   mach_msg_size_t max_size,
77 			   mach_port_t rcv_name,
78 			   mach_msg_option_t option,
79 			   mach_msg_timeout_t timeout)
80 {
81   mig_reply_header_t *request, *reply;
82   mach_msg_return_t mr;
83 
84   if (max_size == 0)
85     {
86 #ifdef MACH_RCV_LARGE
87       option |= MACH_RCV_LARGE;
88       max_size = 2 * __vm_page_size; /* Generic.  Good? XXX */
89 #else
90       max_size = 4 * __vm_page_size; /* XXX */
91 #endif
92     }
93 
94   request = __alloca (max_size);
95   reply = __alloca (max_size);
96 
97   while (1)
98     {
99     get_request:
100       mr = __mach_msg (&request->Head, MACH_RCV_MSG|option,
101 		       0, max_size, rcv_name,
102 		       timeout, MACH_PORT_NULL);
103       while (mr == MACH_MSG_SUCCESS)
104 	{
105 	  /* We have a request message.
106 	     Pass it to DEMUX for processing.  */
107 
108 	  (void) (*demux) (&request->Head, &reply->Head);
109 	  assert (reply->Head.msgh_size <= max_size);
110 
111 	  switch (reply->RetCode)
112 	    {
113 	    case KERN_SUCCESS:
114 	      /* Hunky dory.  */
115 	      break;
116 
117 	    case MIG_NO_REPLY:
118 	      /* The server function wanted no reply sent.
119 		 Loop for another request.  */
120 	      goto get_request;
121 
122 	    default:
123 	      /* Some error; destroy the request message to release any
124 		 port rights or VM it holds.  Don't destroy the reply port
125 		 right, so we can send an error message.  */
126 	      request->Head.msgh_remote_port = MACH_PORT_NULL;
127 	      __mach_msg_destroy (&request->Head);
128 	      break;
129 	    }
130 
131 	  if (reply->Head.msgh_remote_port == MACH_PORT_NULL)
132 	    {
133 	      /* No reply port, so destroy the reply.  */
134 	      if (reply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
135 		__mach_msg_destroy (&reply->Head);
136 	      goto get_request;
137 	    }
138 
139 	  /* Send the reply and the get next request.  */
140 
141 	  {
142 	    /* Swap the request and reply buffers.  mach_msg will read the
143 	       reply message from the buffer we pass and write the new
144 	       request message to the same buffer.  */
145 	    void *tmp = request;
146 	    request = reply;
147 	    reply = tmp;
148 	  }
149 
150 	  mr = __mach_msg (&request->Head,
151 			   MACH_SEND_MSG|MACH_RCV_MSG|option,
152 			   request->Head.msgh_size, max_size, rcv_name,
153 			   timeout, MACH_PORT_NULL);
154 	}
155 
156       /* A message error occurred.  */
157 
158       switch (mr)
159 	{
160 	case MACH_RCV_TOO_LARGE:
161 #ifdef MACH_RCV_LARGE
162 	  /* The request message is larger than MAX_SIZE, and has not
163 	     been dequeued.  The message header has the actual size of
164 	     the message.  We recurse here in hopes that the compiler
165 	     will optimize the tail-call and allocate some more stack
166 	     space instead of way too much.  */
167 	  return __mach_msg_server_timeout (demux, request->Head.msgh_size,
168 					    rcv_name, option, timeout);
169 #else
170 	  /* XXX the kernel has destroyed the msg */
171 	  break;
172 #endif
173 
174 	case MACH_SEND_INVALID_DEST:
175 	  /* The reply can't be delivered, so destroy it.  This error
176 	     indicates only that the requester went away, so we
177 	     continue and get the next request.  */
178 	  __mach_msg_destroy (&request->Head);
179 	  break;
180 
181 	default:
182 	  /* Some other form of lossage; return to caller.  */
183 	  return mr;
184 	}
185     }
186 }
weak_alias(__mach_msg_server_timeout,mach_msg_server_timeout)187 weak_alias (__mach_msg_server_timeout, mach_msg_server_timeout)
188 
189 mach_msg_return_t
190 __mach_msg_server (boolean_t (*demux) (mach_msg_header_t *in,
191 				       mach_msg_header_t *out),
192 		   mach_msg_size_t max_size,
193 		   mach_port_t rcv_name)
194 {
195   return __mach_msg_server_timeout (demux, max_size, rcv_name,
196 				    MACH_MSG_OPTION_NONE,
197 				    MACH_MSG_TIMEOUT_NONE);
198 }
199 weak_alias (__mach_msg_server, mach_msg_server)
200