6bd3f2629551d55a236839d3d8f0e084b5f47e2e
[reactos.git] / reactos / ntoskrnl / lpc / send.c
1 /* $Id: send.c,v 1.14 2004/01/07 21:13:22 ea Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/lpc/send.c
6 * PURPOSE: Communication mechanism
7 * PROGRAMMER: David Welch (welch@cwcom.net)
8 * UPDATE HISTORY:
9 * Created 22/05/98
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <internal/ob.h>
16 #include <internal/port.h>
17 #include <internal/dbg.h>
18 #include <internal/safe.h>
19
20 #define NDEBUG
21 #include <internal/debug.h>
22
23
24 /**********************************************************************
25 * NAME
26 * LpcSendTerminationPort/2
27 *
28 * DESCRIPTION
29 *
30 * ARGUMENTS
31 *
32 * RETURN VALUE
33 *
34 * REVISIONS
35 */
36 NTSTATUS STDCALL
37 LpcSendTerminationPort (IN PEPORT Port,
38 IN TIME CreationTime)
39 {
40 NTSTATUS Status;
41 LPC_TERMINATION_MESSAGE Msg;
42
43 #ifdef __USE_NT_LPC__
44 Msg.Header.MessageType = LPC_NEW_MESSAGE;
45 #endif
46 Msg.CreationTime = CreationTime;
47 Status = LpcRequestPort (Port, &Msg.Header);
48 return(Status);
49 }
50
51
52 /**********************************************************************
53 * NAME
54 * LpcSendDebugMessagePort/3
55 *
56 * DESCRIPTION
57 *
58 * ARGUMENTS
59 *
60 * RETURN VALUE
61 *
62 * REVISIONS
63 */
64 NTSTATUS STDCALL
65 LpcSendDebugMessagePort (IN PEPORT Port,
66 IN PLPC_DBG_MESSAGE Message,
67 OUT PLPC_DBG_MESSAGE Reply)
68 {
69 NTSTATUS Status;
70 KIRQL oldIrql;
71 PQUEUEDMESSAGE ReplyMessage;
72
73 Status = EiReplyOrRequestPort(Port,
74 &Message->Header,
75 LPC_REQUEST,
76 Port);
77 if (!NT_SUCCESS(Status))
78 {
79 ObDereferenceObject(Port);
80 return(Status);
81 }
82 KeReleaseSemaphore(&Port->OtherPort->Semaphore, IO_NO_INCREMENT, 1, FALSE);
83
84 /*
85 * Wait for a reply
86 */
87 KeWaitForSingleObject(&Port->Semaphore,
88 UserRequest,
89 UserMode,
90 FALSE,
91 NULL);
92
93 /*
94 * Dequeue the reply
95 */
96 KeAcquireSpinLock(&Port->Lock, &oldIrql);
97 ReplyMessage = EiDequeueMessagePort(Port);
98 KeReleaseSpinLock(&Port->Lock, oldIrql);
99 memcpy(Reply, &ReplyMessage->Message, ReplyMessage->Message.MessageSize);
100 ExFreePool(ReplyMessage);
101
102 return(STATUS_SUCCESS);
103 }
104
105
106 /**********************************************************************
107 * NAME
108 * LpcRequestPort/2
109 *
110 * DESCRIPTION
111 *
112 * ARGUMENTS
113 *
114 * RETURN VALUE
115 *
116 * REVISIONS
117 * 2002-03-01 EA
118 * I investigated this function a bit more in depth.
119 * It looks like the legal values for the MessageType field in the
120 * message to send are in the range LPC_NEW_MESSAGE .. LPC_CLIENT_DIED,
121 * but LPC_DATAGRAM is explicitly forbidden.
122 *
123 * @implemented
124 */
125 NTSTATUS STDCALL LpcRequestPort (IN PEPORT Port,
126 IN PLPC_MESSAGE LpcMessage)
127 {
128 NTSTATUS Status;
129
130 DPRINT("LpcRequestPort(PortHandle %08x, LpcMessage %08x)\n", Port, LpcMessage);
131
132 #ifdef __USE_NT_LPC__
133 /* Check the message's type */
134 if (LPC_NEW_MESSAGE == LpcMessage->MessageType)
135 {
136 LpcMessage->MessageType = LPC_DATAGRAM;
137 }
138 else if (LPC_DATAGRAM == LpcMessage->MessageType)
139 {
140 return STATUS_INVALID_PARAMETER;
141 }
142 else if (LpcMessage->MessageType > LPC_CLIENT_DIED)
143 {
144 return STATUS_INVALID_PARAMETER;
145 }
146 /* Check the range offset */
147 if (0 != LpcMessage->VirtualRangesOffset)
148 {
149 return STATUS_INVALID_PARAMETER;
150 }
151 #endif
152
153 Status = EiReplyOrRequestPort(Port,
154 LpcMessage,
155 LPC_DATAGRAM,
156 Port);
157 KeReleaseSemaphore( &Port->Semaphore, IO_NO_INCREMENT, 1, FALSE );
158
159 return(Status);
160 }
161
162
163 /**********************************************************************
164 * NAME
165 * NtRequestPort/2
166 *
167 * DESCRIPTION
168 *
169 * ARGUMENTS
170 *
171 * RETURN VALUE
172 *
173 * REVISIONS
174 *
175 * @implemented
176 */
177 NTSTATUS STDCALL NtRequestPort (IN HANDLE PortHandle,
178 IN PLPC_MESSAGE LpcMessage)
179 {
180 NTSTATUS Status;
181 PEPORT Port;
182
183 DPRINT("NtRequestPort(PortHandle %x LpcMessage %x)\n", PortHandle,
184 LpcMessage);
185
186 Status = ObReferenceObjectByHandle(PortHandle,
187 PORT_ALL_ACCESS,
188 ExPortType,
189 UserMode,
190 (PVOID*)&Port,
191 NULL);
192 if (!NT_SUCCESS(Status))
193 {
194 DPRINT("NtRequestPort() = %x\n", Status);
195 return(Status);
196 }
197
198 Status = LpcRequestPort(Port->OtherPort,
199 LpcMessage);
200
201 ObDereferenceObject(Port);
202 return(Status);
203 }
204
205
206 /**********************************************************************
207 * NAME
208 * NtRequestWaitReplyPort/3
209 *
210 * DESCRIPTION
211 *
212 * ARGUMENTS
213 *
214 * RETURN VALUE
215 *
216 * REVISIONS
217 *
218 * @implemented
219 */
220 NTSTATUS STDCALL
221 NtRequestWaitReplyPort (IN HANDLE PortHandle,
222 PLPC_MESSAGE UnsafeLpcRequest,
223 PLPC_MESSAGE UnsafeLpcReply)
224 {
225 NTSTATUS Status;
226 PEPORT Port;
227 PQUEUEDMESSAGE Message;
228 KIRQL oldIrql;
229 PLPC_MESSAGE LpcRequest;
230 USHORT LpcRequestMessageSize;
231
232 DPRINT("NtRequestWaitReplyPort(PortHandle %x, LpcRequest %x, "
233 "LpcReply %x)\n", PortHandle, UnsafeLpcRequest, UnsafeLpcReply);
234
235 Status = ObReferenceObjectByHandle(PortHandle,
236 PORT_ALL_ACCESS,
237 ExPortType,
238 UserMode,
239 (PVOID*)&Port,
240 NULL);
241 if (!NT_SUCCESS(Status))
242 {
243 return(Status);
244 }
245
246 Status = MmCopyFromCaller(&LpcRequestMessageSize,
247 &UnsafeLpcRequest->MessageSize,
248 sizeof(USHORT));
249 if (!NT_SUCCESS(Status))
250 {
251 ObDereferenceObject(Port);
252 return(Status);
253 }
254 if (LpcRequestMessageSize > (sizeof(LPC_MESSAGE) + MAX_MESSAGE_DATA))
255 {
256 ObDereferenceObject(Port);
257 return(STATUS_PORT_MESSAGE_TOO_LONG);
258 }
259 LpcRequest = ExAllocatePool(NonPagedPool, LpcRequestMessageSize);
260 if (LpcRequest == NULL)
261 {
262 ObDereferenceObject(Port);
263 return(STATUS_NO_MEMORY);
264 }
265 Status = MmCopyFromCaller(LpcRequest, UnsafeLpcRequest,
266 LpcRequestMessageSize);
267 if (!NT_SUCCESS(Status))
268 {
269 ExFreePool(LpcRequest);
270 ObDereferenceObject(Port);
271 return(Status);
272 }
273 LpcRequestMessageSize = LpcRequest->MessageSize;
274 if (LpcRequestMessageSize > (sizeof(LPC_MESSAGE) + MAX_MESSAGE_DATA))
275 {
276 ExFreePool(LpcRequest);
277 ObDereferenceObject(Port);
278 return(STATUS_PORT_MESSAGE_TOO_LONG);
279 }
280 if (LpcRequest->DataSize != (LpcRequest->MessageSize - sizeof(LPC_MESSAGE)))
281 {
282 ExFreePool(LpcRequest);
283 ObDereferenceObject(Port);
284 return(STATUS_PORT_MESSAGE_TOO_LONG);
285 }
286
287 Status = EiReplyOrRequestPort(Port->OtherPort,
288 LpcRequest,
289 LPC_REQUEST,
290 Port);
291 if (!NT_SUCCESS(Status))
292 {
293 DbgPrint("Enqueue failed\n");
294 ExFreePool(LpcRequest);
295 ObDereferenceObject(Port);
296 return(Status);
297 }
298 ExFreePool(LpcRequest);
299 KeReleaseSemaphore (&Port->OtherPort->Semaphore, IO_NO_INCREMENT,
300 1, FALSE);
301
302 /*
303 * Wait for a reply
304 */
305 Status = KeWaitForSingleObject(&Port->Semaphore,
306 UserRequest,
307 UserMode,
308 FALSE,
309 NULL);
310 if (Status == STATUS_SUCCESS)
311 {
312
313 /*
314 * Dequeue the reply
315 */
316 KeAcquireSpinLock(&Port->Lock, &oldIrql);
317 Message = EiDequeueMessagePort(Port);
318 KeReleaseSpinLock(&Port->Lock, oldIrql);
319 if (Message)
320 {
321 DPRINT("Message->Message.MessageSize %d\n",
322 Message->Message.MessageSize);
323 Status = MmCopyToCaller(UnsafeLpcReply, &Message->Message,
324 Message->Message.MessageSize);
325 ExFreePool(Message);
326 }
327 else
328 Status = STATUS_UNSUCCESSFUL;
329 }
330 else
331 {
332 if (NT_SUCCESS(Status))
333 {
334 Status = STATUS_UNSUCCESSFUL;
335 }
336 }
337 ObDereferenceObject(Port);
338
339 return(Status);
340 }
341
342
343 /**********************************************************************
344 * NAME
345 * NtWriteRequestData/6
346 *
347 * DESCRIPTION
348 *
349 * ARGUMENTS
350 *
351 * RETURN VALUE
352 *
353 * REVISIONS
354 */
355 NTSTATUS STDCALL NtWriteRequestData (HANDLE PortHandle,
356 PLPC_MESSAGE Message,
357 ULONG Index,
358 PVOID Buffer,
359 ULONG BufferLength,
360 PULONG ReturnLength)
361 {
362 UNIMPLEMENTED;
363 return(STATUS_NOT_IMPLEMENTED);
364 }
365
366
367 /* EOF */