ReactOS 0.4.15-dev-7961-gdcf9eb0
complete.c
Go to the documentation of this file.
1/*
2* PROJECT: ReactOS Kernel
3* LICENSE: GPL - See COPYING in the top level directory
4* FILE: ntoskrnl/lpc/complete.c
5* PURPOSE: Local Procedure Call: Connection Completion
6* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7*/
8
9/* INCLUDES ******************************************************************/
10
11#include <ntoskrnl.h>
12#define NDEBUG
13#include <debug.h>
14
15/* PRIVATE FUNCTIONS *********************************************************/
16
17VOID
20{
21 PAGED_CODE();
22
23 /* Make sure the thread isn't dying and it has a valid chain */
26 {
27 /* Remove it from the list and reinitialize it */
30 }
31}
32
33/* PUBLIC FUNCTIONS **********************************************************/
34
35/*
36 * @implemented
37 */
41 IN PVOID PortContext OPTIONAL,
43 IN BOOLEAN AcceptConnection,
44 IN OUT PPORT_VIEW ServerView OPTIONAL,
46{
49 PORT_VIEW CapturedServerView;
50 PORT_MESSAGE CapturedReplyMessage;
51 ULONG ConnectionInfoLength;
53 PLPCP_CONNECTION_MESSAGE ConnectMessage;
55 PVOID ClientSectionToMap = NULL;
57 PEPROCESS ClientProcess;
60
61 PAGED_CODE();
62
64 "Context: %p. Message: %p. Accept: %lx. Views: %p/%p\n",
65 PortContext,
67 AcceptConnection,
68 ClientView,
69 ServerView);
70
71 /* Check if the call comes from user mode */
73 {
75 {
76 /* Probe the PortHandle */
77 ProbeForWriteHandle(PortHandle);
78
79 /* Probe the basic ReplyMessage structure */
80 ProbeForRead(ReplyMessage, sizeof(*ReplyMessage), sizeof(ULONG));
81 CapturedReplyMessage = *(volatile PORT_MESSAGE*)ReplyMessage;
82 ConnectionInfoLength = CapturedReplyMessage.u1.s1.DataLength;
83
84 /* Probe the connection info */
85 ProbeForRead(ReplyMessage + 1, ConnectionInfoLength, 1);
86
87 /* The following parameters are optional */
88
89 /* Capture the server view */
90 if (ServerView)
91 {
92 ProbeForWrite(ServerView, sizeof(*ServerView), sizeof(ULONG));
93 CapturedServerView = *(volatile PORT_VIEW*)ServerView;
94
95 /* Validate the size of the server view */
96 if (CapturedServerView.Length != sizeof(CapturedServerView))
97 {
98 /* Invalid size */
100 }
101 }
102
103 /* Capture the client view */
104 if (ClientView)
105 {
106 ProbeForWrite(ClientView, sizeof(*ClientView), sizeof(ULONG));
107
108 /* Validate the size of the client view */
109 if (((volatile REMOTE_PORT_VIEW*)ClientView)->Length != sizeof(*ClientView))
110 {
111 /* Invalid size */
113 }
114 }
115 }
117 {
118 /* There was an exception, return the exception code */
120 }
121 _SEH2_END;
122 }
123 else
124 {
125 CapturedReplyMessage = *ReplyMessage;
126 ConnectionInfoLength = CapturedReplyMessage.u1.s1.DataLength;
127
128 /* Capture the server view */
129 if (ServerView)
130 {
131 /* Validate the size of the server view */
132 if (ServerView->Length != sizeof(*ServerView))
133 {
134 /* Invalid size */
136 }
137 CapturedServerView = *ServerView;
138 }
139
140 /* Capture the client view */
141 if (ClientView)
142 {
143 /* Validate the size of the client view */
144 if (ClientView->Length != sizeof(*ClientView))
145 {
146 /* Invalid size */
148 }
149 }
150 }
151
152 /* Get the client process and thread */
153 Status = PsLookupProcessThreadByCid(&CapturedReplyMessage.ClientId,
154 &ClientProcess,
155 &ClientThread);
156 if (!NT_SUCCESS(Status)) return Status;
157
158 /* Acquire the LPC Lock */
160
161 /* Make sure that the client wants a reply, and this is the right one */
163 !(CapturedReplyMessage.MessageId) ||
164 (ClientThread->LpcReplyMessageId != CapturedReplyMessage.MessageId))
165 {
166 /* Not the reply asked for, or no reply wanted, fail */
168 ObDereferenceObject(ClientProcess);
171 }
172
173 /* Now get the message and connection message */
175 ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
176
177 /* Get the client and connection port as well */
178 ClientPort = ConnectMessage->ClientPort;
179 ConnectionPort = ClientPort->ConnectionPort;
180
181 /* Make sure that the reply is being sent to the proper server process */
182 if (ConnectionPort->ServerProcess != PsGetCurrentProcess())
183 {
184 /* It's not, so fail */
186 ObDereferenceObject(ClientProcess);
189 }
190
191 /* At this point, don't let other accept attempts happen */
192 ClientThread->LpcReplyMessage = NULL;
193 ClientThread->LpcReplyMessageId = 0;
194
195 /* Clear the client port for now as well, then release the lock */
196 ConnectMessage->ClientPort = NULL;
198
199 /* Check the connection information length */
200 if (ConnectionInfoLength > ConnectionPort->MaxConnectionInfoLength)
201 {
202 /* Normalize it since it's too large */
203 ConnectionInfoLength = ConnectionPort->MaxConnectionInfoLength;
204 }
205
206 /* Set the sizes of our reply message */
207 Message->Request.u1.s1.DataLength = (CSHORT)ConnectionInfoLength +
209 Message->Request.u1.s1.TotalLength = sizeof(LPCP_MESSAGE) +
210 Message->Request.u1.s1.DataLength;
211
212 /* Setup the reply message */
213 Message->Request.u2.s2.Type = LPC_REPLY;
214 Message->Request.u2.s2.DataInfoOffset = 0;
215 Message->Request.ClientId = CapturedReplyMessage.ClientId;
216 Message->Request.MessageId = CapturedReplyMessage.MessageId;
217 Message->Request.ClientViewSize = 0;
218
220 {
221 RtlCopyMemory(ConnectMessage + 1, ReplyMessage + 1, ConnectionInfoLength);
222 }
224 {
226 _SEH2_YIELD(goto Cleanup);
227 }
228 _SEH2_END;
229
230 /* At this point, if the caller refused the connection, go to cleanup */
231 if (!AcceptConnection)
232 {
233 DPRINT1("LPC connection was refused\n");
234 goto Cleanup;
235 }
236
237 /* Otherwise, create the actual port */
240 NULL,
242 NULL,
243 sizeof(LPCP_PORT_OBJECT),
244 0,
245 0,
246 (PVOID*)&ServerPort);
247 if (!NT_SUCCESS(Status)) goto Cleanup;
248
249 /* Set it up */
251 ServerPort->PortContext = PortContext;
253 ServerPort->MaxMessageLength = ConnectionPort->MaxMessageLength;
254 InitializeListHead(&ServerPort->LpcReplyChainHead);
255 InitializeListHead(&ServerPort->LpcDataInfoChainHead);
256
257 /* Reference the connection port until we're fully setup */
258 ObReferenceObject(ConnectionPort);
259
260 /* Link the ports together */
261 ServerPort->ConnectionPort = ConnectionPort;
262 ServerPort->ConnectedPort = ClientPort;
263 ClientPort->ConnectedPort = ServerPort;
264
265 /* Also set the creator CID */
266 ServerPort->Creator = PsGetCurrentThread()->Cid;
267 ClientPort->Creator = Message->Request.ClientId;
268
269 /* Get the section associated and then clear it, while inside the lock */
271 ClientSectionToMap = ConnectMessage->SectionToMap;
272 ConnectMessage->SectionToMap = NULL;
274
275 /* Now check if there's a client section */
276 if (ClientSectionToMap)
277 {
278 /* Setup the offset */
279 SectionOffset.QuadPart = ConnectMessage->ClientView.SectionOffset;
280
281 /* Map the section */
282 Status = MmMapViewOfSection(ClientSectionToMap,
284 &ServerPort->ClientSectionBase,
285 0,
286 0,
288 &ConnectMessage->ClientView.ViewSize,
289 ViewUnmap,
290 0,
292
293 /* Update the offset and check for mapping status */
294 ConnectMessage->ClientView.SectionOffset = SectionOffset.LowPart;
295 if (NT_SUCCESS(Status))
296 {
297 /* Set the view base */
298 ConnectMessage->ClientView.ViewRemoteBase = ServerPort->
299 ClientSectionBase;
300
301 /* Save and reference the mapping process */
302 ServerPort->MappingProcess = PsGetCurrentProcess();
303 ObReferenceObject(ServerPort->MappingProcess);
304 }
305 else
306 {
307 /* Otherwise, quit */
309 DPRINT1("Client section mapping failed: %lx\n", Status);
311 "View base, offset, size: %p %lx %p\n",
312 ServerPort->ClientSectionBase,
313 ConnectMessage->ClientView.ViewSize,
315 goto Cleanup;
316 }
317 }
318
319 /* Check if there's a server section */
320 if (ServerView)
321 {
322 /* FIXME: TODO */
323 UNREFERENCED_PARAMETER(CapturedServerView);
324 ASSERT(FALSE);
325 }
326
327 /* Reference the server port until it's fully inserted */
329
330 /* Insert the server port in the namespace */
332 NULL,
334 0,
335 NULL,
336 &Handle);
337 if (!NT_SUCCESS(Status))
338 {
339 /* We failed, remove the extra reference and cleanup */
341 goto Cleanup;
342 }
343
344 /* Enter SEH to write back the results */
346 {
347 /* Check if the caller gave a client view */
348 if (ClientView)
349 {
350 /* Fill it out */
351 ClientView->ViewBase = ConnectMessage->ClientView.ViewRemoteBase;
352 ClientView->ViewSize = ConnectMessage->ClientView.ViewSize;
353 }
354
355 /* Return the handle to user mode */
356 *PortHandle = Handle;
357 }
359 {
360 /* Cleanup and return the exception code */
364 _SEH2_YIELD(goto Cleanup);
365 }
366 _SEH2_END;
367
369 "Handle: %p. Messages: %p/%p. Ports: %p/%p/%p\n",
370 Handle,
371 Message,
372 ConnectMessage,
375 ConnectionPort);
376
377 /* If there was no port context, use the handle by default */
378 if (!PortContext) ServerPort->PortContext = Handle;
379 ServerPort->ClientThread = ClientThread;
380
381 /* Set this message as the LPC Reply message while holding the lock */
383 ClientThread->LpcReplyMessage = Message;
385
386 /* Clear the thread pointer so it doesn't get cleaned later */
388
389 /* Remove the extra reference we had added */
391
392Cleanup:
393 /* If there was a section, dereference it */
394 if (ClientSectionToMap) ObDereferenceObject(ClientSectionToMap);
395
396 /* Check if we got here while still having a client thread */
397 if (ClientThread)
398 {
400 ClientThread->LpcReplyMessage = Message;
403 LpcpCompleteWait(&ClientThread->LpcReplySemaphore);
405 }
406
407 /* Dereference the client port if we have one, and the process */
409 "Status: %lx. Thread: %p. Process: [%.16s]\n",
410 Status,
412 ClientProcess->ImageFileName);
414 ObDereferenceObject(ClientProcess);
415 return Status;
416}
417
418/*
419 * @implemented
420 */
422NTAPI
424{
429
430 PAGED_CODE();
431 LPCTRACE(LPC_COMPLETE_DEBUG, "Handle: %p\n", PortHandle);
432
433 /* Get the Port Object */
438 (PVOID*)&Port,
439 NULL);
440 if (!NT_SUCCESS(Status)) return Status;
441
442 /* Make sure this is a connection port */
444 {
445 /* It isn't, fail */
448 }
449
450 /* Acquire the lock */
452
453 /* Make sure we have a client thread */
454 if (!Port->ClientThread)
455 {
456 /* We don't, fail */
460 }
461
462 /* Get the thread */
463 Thread = Port->ClientThread;
464
465 /* Make sure it has a reply message */
467 {
468 /* It doesn't, quit */
471 return STATUS_SUCCESS;
472 }
473
474 /* Clear the client thread and wake it up */
475 Port->ClientThread = NULL;
477
478 /* Release the lock and wait for an answer */
480 LpcpCompleteWait(&Thread->LpcReplySemaphore);
481
482 /* Dereference the Thread and Port and return */
485 LPCTRACE(LPC_COMPLETE_DEBUG, "Port: %p. Thread: %p\n", Port, Thread);
486 return Status;
487}
488
489/* EOF */
#define PAGED_CODE()
static const INTERNET_PORT ServerPort
Definition: CWebService.cpp:11
UINT CALLBACK ClientThread(_Inout_ PVOID Parameter)
unsigned char BOOLEAN
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
VOID NTAPI LpcpPrepareToWakeClient(IN PETHREAD Thread)
Definition: complete.c:19
NTSTATUS NTAPI NtAcceptConnectPort(OUT PHANDLE PortHandle, IN PVOID PortContext OPTIONAL, IN PPORT_MESSAGE ReplyMessage, IN BOOLEAN AcceptConnection, IN OUT PPORT_VIEW ServerView OPTIONAL, OUT PREMOTE_PORT_VIEW ClientView OPTIONAL)
Definition: complete.c:40
NTSTATUS NTAPI NtCompleteConnectPort(IN HANDLE PortHandle)
Definition: complete.c:423
#define NULL
Definition: types.h:112
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
static const WCHAR Message[]
Definition: register.c:74
static const WCHAR Cleanup[]
Definition: register.c:80
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
VOID NTAPI ProbeForRead(IN CONST VOID *Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:102
VOID NTAPI ProbeForWrite(IN PVOID Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:143
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
_Outptr_ PFLT_PORT * ClientPort
Definition: fltkernel.h:1891
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
ULONG Handle
Definition: gdb_input.c:15
Status
Definition: gdiplustypes.h:25
VOID FASTCALL KeReleaseGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex)
Definition: gmutex.c:53
VOID FASTCALL KeAcquireGuardedMutex(IN PKGUARDED_MUTEX GuardedMutex)
Definition: gmutex.c:42
CPPORT Port[4]
Definition: headless.c:35
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
KGUARDED_MUTEX LpcpLock
Definition: port.c:20
POBJECT_TYPE LpcPortObjectType
Definition: port.c:17
#define LPCTRACE(x, fmt,...)
Definition: lpc.h:49
#define LPC_COMPLETE_DEBUG
Definition: lpc.h:22
#define LpcpCompleteWait(s)
Definition: lpc_x.h:88
FORCEINLINE PLPCP_MESSAGE LpcpGetMessageFromThread(IN PETHREAD Thread)
Definition: lpc_x.h:129
#define LPCP_COMMUNICATION_PORT
Definition: lpctypes.h:56
#define PORT_ALL_ACCESS
Definition: lpctypes.h:47
#define LPCP_PORT_TYPE_MASK
Definition: lpctypes.h:58
struct _LPCP_MESSAGE LPCP_MESSAGE
struct _LPCP_CONNECTION_MESSAGE * PLPCP_CONNECTION_MESSAGE
#define ASSERT(a)
Definition: mode.c:44
#define LPC_REPLY
Definition: port.c:94
#define KernelMode
Definition: asm.h:34
#define KeGetPreviousMode()
Definition: ketypes.h:1115
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID _In_ ULONG_PTR _In_ SIZE_T _Inout_opt_ PLARGE_INTEGER SectionOffset
Definition: mmfuncs.h:407
#define PAGE_READWRITE
Definition: nt_native.h:1304
@ ViewUnmap
Definition: nt_native.h:1279
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
NTSTATUS NTAPI PsLookupProcessThreadByCid(IN PCLIENT_ID Cid, OUT PEPROCESS *Process OPTIONAL, OUT PETHREAD *Thread)
Definition: process.c:961
PVOID *typedef PHANDLE
Definition: ntsecpkg.h:455
#define STATUS_INVALID_PORT_HANDLE
Definition: ntstatus.h:302
#define STATUS_REPLY_MESSAGE_MISMATCH
Definition: ntstatus.h:675
NTSTATUS NTAPI ObCloseHandle(IN HANDLE Handle, IN KPROCESSOR_MODE AccessMode)
Definition: obhandle.c:3379
NTSTATUS NTAPI ObInsertObject(IN PVOID Object, IN PACCESS_STATE AccessState OPTIONAL, IN ACCESS_MASK DesiredAccess, IN ULONG ObjectPointerBias, OUT PVOID *NewObject OPTIONAL, OUT PHANDLE Handle)
Definition: obhandle.c:2935
NTSTATUS NTAPI ObCreateObject(IN KPROCESSOR_MODE ProbeMode OPTIONAL, IN POBJECT_TYPE Type, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN KPROCESSOR_MODE AccessMode, IN OUT PVOID ParseContext OPTIONAL, IN ULONG ObjectSize, IN ULONG PagedPoolCharge OPTIONAL, IN ULONG NonPagedPoolCharge OPTIONAL, OUT PVOID *Object)
Definition: oblife.c:1039
NTSTATUS NTAPI ObReferenceObjectByHandle(IN HANDLE Handle, IN ACCESS_MASK DesiredAccess, IN POBJECT_TYPE ObjectType, IN KPROCESSOR_MODE AccessMode, OUT PVOID *Object, OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL)
Definition: obref.c:494
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:159
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:34
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:162
#define ProbeForWriteHandle(Ptr)
Definition: probe.h:43
NTSTATUS NTAPI MmMapViewOfSection(IN PVOID SectionObject, IN PEPROCESS Process, IN OUT PVOID *BaseAddress, IN ULONG_PTR ZeroBits, IN SIZE_T CommitSize, IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, IN OUT PSIZE_T ViewSize, IN SECTION_INHERIT InheritDisposition, IN ULONG AllocationType, IN ULONG Protect)
Definition: section.c:3996
#define STATUS_SUCCESS
Definition: shellext.h:65
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
USHORT Flags
Definition: cportlib.h:31
ULONG LpcExitThreadCalled
Definition: pstypes.h:1215
LIST_ENTRY LpcReplyChain
Definition: pstypes.h:1108
PLPCP_PORT_OBJECT ClientPort
Definition: lpctypes.h:257
PEPROCESS ServerProcess
Definition: lpctypes.h:225
ULONG MaxConnectionInfoLength
Definition: lpctypes.h:229
CLIENT_ID ClientId
Definition: winternl.h:1751
#define NTAPI
Definition: typedefs.h:36
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define IN
Definition: typedefs.h:39
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
short CSHORT
Definition: umtypes.h:127
BOOL WINAPI ReplyMessage(_In_ LRESULT)
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
#define ObDereferenceObject
Definition: obfuncs.h:203
#define ObReferenceObject
Definition: obfuncs.h:204
#define PsGetCurrentProcess
Definition: psfuncs.h:17
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103