- split logoff and shutdown resources
[reactos.git] / reactos / ntoskrnl / lpc / send.c
1 /* $Id$
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 *
8 * PROGRAMMERS: David Welch (welch@cwcom.net)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14
15 #define NDEBUG
16 #include <internal/debug.h>
17
18
19 /**********************************************************************
20 * NAME
21 * LpcSendTerminationPort/2
22 *
23 * DESCRIPTION
24 *
25 * ARGUMENTS
26 *
27 * RETURN VALUE
28 *
29 * REVISIONS
30 */
31 NTSTATUS STDCALL
32 LpcSendTerminationPort (IN PEPORT Port,
33 IN LARGE_INTEGER CreateTime)
34 {
35 NTSTATUS Status;
36 CLIENT_DIED_MSG Msg;
37
38 #ifdef __USE_NT_LPC__
39 Msg.h.u2.s2.Type = LPC_CLIENT_DIED;
40 #endif
41 Msg.h.u1.s1.TotalLength = sizeof(Msg);
42 Msg.h.u1.s1.DataLength = sizeof(Msg) - sizeof(PORT_MESSAGE);
43 Msg.CreateTime = CreateTime;
44 Status = LpcRequestPort (Port, &Msg.h);
45 return(Status);
46 }
47
48
49 /**********************************************************************
50 * NAME
51 * LpcSendDebugMessagePort/3
52 *
53 * DESCRIPTION
54 *
55 * ARGUMENTS
56 *
57 * RETURN VALUE
58 *
59 * REVISIONS
60 */
61 NTSTATUS STDCALL
62 LpcSendDebugMessagePort (IN PEPORT Port,
63 IN PDBGKM_MSG Message,
64 OUT PDBGKM_MSG Reply)
65 {
66 NTSTATUS Status;
67 KIRQL oldIrql;
68 PQUEUEDMESSAGE ReplyMessage;
69
70 Status = EiReplyOrRequestPort(Port,
71 &Message->h,
72 LPC_REQUEST,
73 Port);
74 if (!NT_SUCCESS(Status))
75 {
76 ObDereferenceObject(Port);
77 return(Status);
78 }
79 KeReleaseSemaphore(&Port->OtherPort->Semaphore, IO_NO_INCREMENT, 1, FALSE);
80
81 /*
82 * Wait for a reply
83 */
84 KeWaitForSingleObject(&Port->Semaphore,
85 UserRequest,
86 UserMode,
87 FALSE,
88 NULL);
89
90 /*
91 * Dequeue the reply
92 */
93 KeAcquireSpinLock(&Port->Lock, &oldIrql);
94 ReplyMessage = EiDequeueMessagePort(Port);
95 KeReleaseSpinLock(&Port->Lock, oldIrql);
96 memcpy(Reply, &ReplyMessage->Message, ReplyMessage->Message.u1.s1.TotalLength);
97 ExFreePool(ReplyMessage);
98
99 return(STATUS_SUCCESS);
100 }
101
102
103 /**********************************************************************
104 * NAME
105 * LpcRequestPort/2
106 *
107 * DESCRIPTION
108 *
109 * ARGUMENTS
110 *
111 * RETURN VALUE
112 *
113 * REVISIONS
114 * 2002-03-01 EA
115 * I investigated this function a bit more in depth.
116 * It looks like the legal values for the MessageType field in the
117 * message to send are in the range LPC_NEW_MESSAGE .. LPC_CLIENT_DIED,
118 * but LPC_DATAGRAM is explicitly forbidden.
119 *
120 * @implemented
121 */
122 NTSTATUS STDCALL LpcRequestPort (IN PEPORT Port,
123 IN PPORT_MESSAGE LpcMessage)
124 {
125 NTSTATUS Status;
126
127 DPRINT("LpcRequestPort(PortHandle %08x, LpcMessage %08x)\n", Port, LpcMessage);
128
129 #ifdef __USE_NT_LPC__
130 /* Check the message's type */
131 if (LPC_NEW_MESSAGE == LpcMessage->u2.s2.Type)
132 {
133 LpcMessage->u2.s2.Type = LPC_DATAGRAM;
134 }
135 else if (LPC_DATAGRAM == LpcMessage->u2.s2.Type)
136 {
137 return STATUS_INVALID_PARAMETER;
138 }
139 else if (LpcMessage->u2.s2.Type > LPC_CLIENT_DIED)
140 {
141 return STATUS_INVALID_PARAMETER;
142 }
143 /* Check the range offset */
144 if (0 != LpcMessage->VirtualRangesOffset)
145 {
146 return STATUS_INVALID_PARAMETER;
147 }
148 #endif
149
150 Status = EiReplyOrRequestPort(Port,
151 LpcMessage,
152 LPC_DATAGRAM,
153 Port);
154 KeReleaseSemaphore( &Port->Semaphore, IO_NO_INCREMENT, 1, FALSE );
155
156 return(Status);
157 }
158
159
160 /**********************************************************************
161 * NAME
162 * NtRequestPort/2
163 *
164 * DESCRIPTION
165 *
166 * ARGUMENTS
167 *
168 * RETURN VALUE
169 *
170 * REVISIONS
171 *
172 * @implemented
173 */
174 NTSTATUS STDCALL NtRequestPort (IN HANDLE PortHandle,
175 IN PPORT_MESSAGE LpcMessage)
176 {
177 NTSTATUS Status;
178 PEPORT Port;
179
180 DPRINT("NtRequestPort(PortHandle %x LpcMessage %x)\n", PortHandle,
181 LpcMessage);
182
183 Status = ObReferenceObjectByHandle(PortHandle,
184 PORT_ALL_ACCESS,
185 LpcPortObjectType,
186 UserMode,
187 (PVOID*)&Port,
188 NULL);
189 if (!NT_SUCCESS(Status))
190 {
191 DPRINT("NtRequestPort() = %x\n", Status);
192 return(Status);
193 }
194
195 Status = LpcRequestPort(Port->OtherPort,
196 LpcMessage);
197
198 ObDereferenceObject(Port);
199 return(Status);
200 }
201
202
203 /**********************************************************************
204 * NAME
205 * NtRequestWaitReplyPort/3
206 *
207 * DESCRIPTION
208 *
209 * ARGUMENTS
210 *
211 * RETURN VALUE
212 *
213 * REVISIONS
214 *
215 * @implemented
216 */
217 NTSTATUS STDCALL
218 NtRequestWaitReplyPort (IN HANDLE PortHandle,
219 PPORT_MESSAGE UnsafeLpcRequest,
220 PPORT_MESSAGE UnsafeLpcReply)
221 {
222 PETHREAD CurrentThread;
223 struct _KPROCESS *AttachedProcess;
224 PEPORT Port;
225 PQUEUEDMESSAGE Message;
226 KIRQL oldIrql;
227 PPORT_MESSAGE LpcRequest;
228 USHORT LpcRequestMessageSize = 0, LpcRequestDataSize = 0;
229 KPROCESSOR_MODE PreviousMode;
230 NTSTATUS Status = STATUS_SUCCESS;
231
232 PreviousMode = ExGetPreviousMode();
233
234 if (PreviousMode != KernelMode)
235 {
236 _SEH_TRY
237 {
238 ProbeForRead(UnsafeLpcRequest,
239 sizeof(PORT_MESSAGE),
240 1);
241 ProbeForWrite(UnsafeLpcReply,
242 sizeof(PORT_MESSAGE),
243 1);
244 LpcRequestMessageSize = UnsafeLpcRequest->u1.s1.TotalLength;
245 }
246 _SEH_HANDLE
247 {
248 Status = _SEH_GetExceptionCode();
249 }
250 _SEH_END;
251
252 if (!NT_SUCCESS(Status))
253 {
254 return Status;
255 }
256 }
257 else
258 {
259 LpcRequestMessageSize = UnsafeLpcRequest->u1.s1.TotalLength;
260 }
261
262 DPRINT("NtRequestWaitReplyPort(PortHandle %x, LpcRequest %x, "
263 "LpcReply %x)\n", PortHandle, UnsafeLpcRequest, UnsafeLpcReply);
264
265 Status = ObReferenceObjectByHandle(PortHandle,
266 PORT_ALL_ACCESS,
267 LpcPortObjectType,
268 UserMode,
269 (PVOID*)&Port,
270 NULL);
271 if (!NT_SUCCESS(Status))
272 {
273 return(Status);
274 }
275
276 if (EPORT_DISCONNECTED == Port->State)
277 {
278 ObDereferenceObject(Port);
279 return STATUS_PORT_DISCONNECTED;
280 }
281
282 /* win32k sometimes needs to KeAttach() the CSRSS process in order to make
283 the PortHandle valid. Now that we've got the EPORT structure from the
284 handle we can undo this, so everything is normal again. Need to
285 re-KeAttach() before returning though */
286 CurrentThread = PsGetCurrentThread();
287 if (&CurrentThread->ThreadsProcess->Pcb == CurrentThread->Tcb.ApcState.Process)
288 {
289 AttachedProcess = NULL;
290 }
291 else
292 {
293 AttachedProcess = CurrentThread->Tcb.ApcState.Process;
294 KeDetachProcess();
295 }
296
297 if (LpcRequestMessageSize > LPC_MAX_MESSAGE_LENGTH)
298 {
299 if (NULL != AttachedProcess)
300 {
301 KeAttachProcess(AttachedProcess);
302 }
303 ObDereferenceObject(Port);
304 return(STATUS_PORT_MESSAGE_TOO_LONG);
305 }
306 LpcRequest = ExAllocatePool(NonPagedPool, LpcRequestMessageSize);
307 if (LpcRequest == NULL)
308 {
309 if (NULL != AttachedProcess)
310 {
311 KeAttachProcess(AttachedProcess);
312 }
313 ObDereferenceObject(Port);
314 return(STATUS_NO_MEMORY);
315 }
316 if (PreviousMode != KernelMode)
317 {
318 _SEH_TRY
319 {
320 RtlCopyMemory(LpcRequest,
321 UnsafeLpcRequest,
322 LpcRequestMessageSize);
323 LpcRequestMessageSize = LpcRequest->u1.s1.TotalLength;
324 LpcRequestDataSize = LpcRequest->u1.s1.DataLength;
325 }
326 _SEH_HANDLE
327 {
328 Status = _SEH_GetExceptionCode();
329 }
330 _SEH_END;
331
332 if (!NT_SUCCESS(Status))
333 {
334 ExFreePool(LpcRequest);
335 if (NULL != AttachedProcess)
336 {
337 KeAttachProcess(AttachedProcess);
338 }
339 ObDereferenceObject(Port);
340 return(Status);
341 }
342 }
343 else
344 {
345 RtlCopyMemory(LpcRequest,
346 UnsafeLpcRequest,
347 LpcRequestMessageSize);
348 LpcRequestMessageSize = LpcRequest->u1.s1.TotalLength;
349 LpcRequestDataSize = LpcRequest->u1.s1.DataLength;
350 }
351
352 if (LpcRequestMessageSize > LPC_MAX_MESSAGE_LENGTH)
353 {
354 ExFreePool(LpcRequest);
355 if (NULL != AttachedProcess)
356 {
357 KeAttachProcess(AttachedProcess);
358 }
359 ObDereferenceObject(Port);
360 return(STATUS_PORT_MESSAGE_TOO_LONG);
361 }
362 if (LpcRequestDataSize > LPC_MAX_DATA_LENGTH)
363 {
364 ExFreePool(LpcRequest);
365 if (NULL != AttachedProcess)
366 {
367 KeAttachProcess(AttachedProcess);
368 }
369 ObDereferenceObject(Port);
370 return(STATUS_PORT_MESSAGE_TOO_LONG);
371 }
372
373 Status = EiReplyOrRequestPort(Port->OtherPort,
374 LpcRequest,
375 LPC_REQUEST,
376 Port);
377 if (!NT_SUCCESS(Status))
378 {
379 DPRINT1("Enqueue failed\n");
380 ExFreePool(LpcRequest);
381 if (NULL != AttachedProcess)
382 {
383 KeAttachProcess(AttachedProcess);
384 }
385 ObDereferenceObject(Port);
386 return(Status);
387 }
388 ExFreePool(LpcRequest);
389 KeReleaseSemaphore (&Port->OtherPort->Semaphore, IO_NO_INCREMENT,
390 1, FALSE);
391
392 /*
393 * Wait for a reply
394 */
395 Status = KeWaitForSingleObject(&Port->Semaphore,
396 UserRequest,
397 UserMode,
398 FALSE,
399 NULL);
400 if (Status == STATUS_SUCCESS)
401 {
402
403 /*
404 * Dequeue the reply
405 */
406 KeAcquireSpinLock(&Port->Lock, &oldIrql);
407 Message = EiDequeueMessagePort(Port);
408 KeReleaseSpinLock(&Port->Lock, oldIrql);
409 if (Message)
410 {
411 DPRINT("Message->Message.u1.s1.TotalLength %d\n",
412 Message->Message.u1.s1.TotalLength);
413 if (PreviousMode != KernelMode)
414 {
415 _SEH_TRY
416 {
417 RtlCopyMemory(UnsafeLpcReply,
418 &Message->Message,
419 Message->Message.u1.s1.TotalLength);
420 }
421 _SEH_HANDLE
422 {
423 Status = _SEH_GetExceptionCode();
424 }
425 _SEH_END;
426 }
427 else
428 {
429 RtlCopyMemory(UnsafeLpcReply,
430 &Message->Message,
431 Message->Message.u1.s1.TotalLength);
432 }
433 ExFreePool(Message);
434 }
435 else
436 Status = STATUS_UNSUCCESSFUL;
437 }
438 else
439 {
440 if (NT_SUCCESS(Status))
441 {
442 Status = STATUS_UNSUCCESSFUL;
443 }
444 }
445 if (NULL != AttachedProcess)
446 {
447 KeAttachProcess(AttachedProcess);
448 }
449 ObDereferenceObject(Port);
450
451 return(Status);
452 }
453
454
455 /**********************************************************************
456 * NAME
457 * NtWriteRequestData/6
458 *
459 * DESCRIPTION
460 *
461 * ARGUMENTS
462 *
463 * RETURN VALUE
464 *
465 * REVISIONS
466 */
467 NTSTATUS STDCALL NtWriteRequestData (HANDLE PortHandle,
468 PPORT_MESSAGE Message,
469 ULONG Index,
470 PVOID Buffer,
471 ULONG BufferLength,
472 PULONG ReturnLength)
473 {
474 UNIMPLEMENTED;
475 return(STATUS_NOT_IMPLEMENTED);
476 }
477
478
479 /* EOF */