3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/lpc/connect.c
6 * PURPOSE: Communication mechanism
8 * PROGRAMMERS: David Welch (welch@cwcom.net)
11 /* INCLUDES *****************************************************************/
15 #include <internal/debug.h>
17 /* GLOBALS *******************************************************************/
19 #define TAG_LPC_CONNECT_MESSAGE TAG('L', 'P', 'C', 'C')
21 /* FUNCTIONS *****************************************************************/
23 /**********************************************************************
34 EiConnectPort(IN PEPORT
* ConnectedPort
,
36 IN PSECTION_OBJECT Section
,
37 IN LARGE_INTEGER SectionOffset
,
39 OUT PVOID
* ClientSendViewBase
,
40 OUT PVOID
* ServerSendViewBase
,
41 OUT PULONG ReceiveViewSize
,
42 OUT PVOID
* ReceiveViewBase
,
43 OUT PULONG MaximumMessageSize
,
44 IN OUT PVOID ConnectData
,
45 IN OUT PULONG ConnectDataLength
)
47 PEPORT_CONNECT_REQUEST_MESSAGE RequestMessage
;
48 ULONG RequestConnectDataLength
;
51 PEPORT_CONNECT_REPLY_MESSAGE CReply
;
55 if (ConnectDataLength
== NULL
)
57 RequestConnectDataLength
= 0;
61 RequestConnectDataLength
= *ConnectDataLength
;
65 * Create a port to represent our side of the connection
67 Status
= ObCreateObject (KernelMode
,
76 if (!NT_SUCCESS(Status
))
80 LpcpInitializePort(OurPort
, EPORT_TYPE_CLIENT_COMM_PORT
, NamedPort
);
83 * Allocate a request message.
85 RequestMessage
= ExAllocatePool(NonPagedPool
,
86 sizeof(EPORT_CONNECT_REQUEST_MESSAGE
) +
87 RequestConnectDataLength
);
88 if (RequestMessage
== NULL
)
90 ObDereferenceObject(OurPort
);
91 return(STATUS_NO_MEMORY
);
95 * Initialize the request message.
97 RequestMessage
->MessageHeader
.DataSize
=
98 sizeof(EPORT_CONNECT_REQUEST_MESSAGE
) + RequestConnectDataLength
-
100 RequestMessage
->MessageHeader
.MessageSize
=
101 sizeof(EPORT_CONNECT_REQUEST_MESSAGE
) + RequestConnectDataLength
;
102 DPRINT("RequestMessageSize %d\n",
103 RequestMessage
->MessageHeader
.MessageSize
);
104 RequestMessage
->MessageHeader
.SectionSize
= 0;
105 RequestMessage
->ConnectingProcess
= PsGetCurrentProcess();
106 ObReferenceObjectByPointer(RequestMessage
->ConnectingProcess
,
107 PROCESS_VM_OPERATION
,
110 RequestMessage
->SendSectionObject
= (struct _SECTION_OBJECT
*)Section
;
111 RequestMessage
->SendSectionOffset
= SectionOffset
;
112 RequestMessage
->SendViewSize
= ViewSize
;
113 RequestMessage
->ConnectDataLength
= RequestConnectDataLength
;
114 if (RequestConnectDataLength
> 0)
116 memcpy(RequestMessage
->ConnectData
, ConnectData
,
117 RequestConnectDataLength
);
121 * Queue the message to the named port
123 EiReplyOrRequestPort(NamedPort
,
124 &RequestMessage
->MessageHeader
,
125 LPC_CONNECTION_REQUEST
,
127 KeReleaseSemaphore(&NamedPort
->Semaphore
, IO_NO_INCREMENT
, 1, FALSE
);
128 ExFreePool(RequestMessage
);
131 * Wait for them to accept our connection
133 KeWaitForSingleObject(&OurPort
->Semaphore
,
140 * Dequeue the response
142 KeAcquireSpinLock (&OurPort
->Lock
, &oldIrql
);
143 Reply
= EiDequeueMessagePort (OurPort
);
144 KeReleaseSpinLock (&OurPort
->Lock
, oldIrql
);
145 CReply
= (PEPORT_CONNECT_REPLY_MESSAGE
)&Reply
->Message
;
148 * Do some initial cleanup.
150 ObDereferenceObject(PsGetCurrentProcess());
153 * Check for connection refusal.
155 if (CReply
->MessageHeader
.MessageType
== LPC_CONNECTION_REFUSED
)
157 ObDereferenceObject(OurPort
);
160 * FIXME: Check what NT does here. Giving the user data back on
161 * connect failure sounds reasonable; it probably wouldn't break
164 if (ConnectDataLength
!= NULL
)
166 *ConnectDataLength
= CReply
->ConnectDataLength
;
167 memcpy(ConnectData
, CReply
->ConnectData
, CReply
->ConnectDataLength
);
169 return(STATUS_PORT_CONNECTION_REFUSED
);
173 * Otherwise we are connected. Copy data back to the client.
175 *ServerSendViewBase
= CReply
->SendServerViewBase
;
176 *ReceiveViewSize
= CReply
->ReceiveClientViewSize
;
177 *ReceiveViewBase
= CReply
->ReceiveClientViewBase
;
178 *MaximumMessageSize
= CReply
->MaximumMessageSize
;
179 if (ConnectDataLength
!= NULL
)
181 *ConnectDataLength
= CReply
->ConnectDataLength
;
182 memcpy(ConnectData
, CReply
->ConnectData
, CReply
->ConnectDataLength
);
186 * Create our view of the send section object.
190 *ClientSendViewBase
= 0;
191 Status
= MmMapViewOfSection(Section
,
192 PsGetCurrentProcess(),
199 0 /* MEM_TOP_DOWN? */,
201 if (!NT_SUCCESS(Status
))
203 /* FIXME: Cleanup here. */
209 * Do the final initialization of our port.
211 OurPort
->State
= EPORT_CONNECTED_CLIENT
;
217 *ConnectedPort
= OurPort
;
218 return(STATUS_SUCCESS
);
221 /**********************************************************************
226 * Connect to a named port and wait for the other side to
227 * accept or reject the connection request.
237 * UserConnectInfoLength
244 NtConnectPort (PHANDLE UnsafeConnectedPortHandle
,
245 PUNICODE_STRING PortName
,
246 PSECURITY_QUALITY_OF_SERVICE Qos
,
247 PLPC_SECTION_WRITE UnsafeWriteMap
,
248 PLPC_SECTION_READ UnsafeReadMap
,
249 PULONG UnsafeMaximumMessageSize
,
250 PVOID UnsafeConnectData
,
251 PULONG UnsafeConnectDataLength
)
253 HANDLE ConnectedPortHandle
;
254 LPC_SECTION_WRITE WriteMap
;
255 LPC_SECTION_READ ReadMap
;
256 ULONG MaximumMessageSize
;
258 ULONG ConnectDataLength
;
259 PSECTION_OBJECT SectionObject
;
260 LARGE_INTEGER SectionOffset
;
261 PEPORT ConnectedPort
;
266 * Copy in write map and partially validate.
268 if (UnsafeWriteMap
!= NULL
)
270 Status
= MmCopyFromCaller(&WriteMap
,
272 sizeof(LPC_SECTION_WRITE
));
273 if (!NT_SUCCESS(Status
))
277 if (WriteMap
.Length
!= sizeof(LPC_SECTION_WRITE
))
279 return(STATUS_INVALID_PARAMETER_4
);
281 SectionOffset
.QuadPart
= WriteMap
.SectionOffset
;
285 WriteMap
.SectionHandle
= INVALID_HANDLE_VALUE
;
289 * Handle connection data.
291 if (UnsafeConnectData
== NULL
)
293 ConnectDataLength
= 0;
298 if (ExGetPreviousMode() == KernelMode
)
300 ConnectDataLength
= *UnsafeConnectDataLength
;
301 ConnectData
= UnsafeConnectData
;
305 Status
= MmCopyFromCaller(&ConnectDataLength
,
306 UnsafeConnectDataLength
,
308 if (!NT_SUCCESS(Status
))
312 ConnectData
= ExAllocatePool(NonPagedPool
, ConnectDataLength
);
313 if (ConnectData
== NULL
&& ConnectDataLength
!= 0)
315 return(STATUS_NO_MEMORY
);
317 Status
= MmCopyFromCaller(ConnectData
,
320 if (!NT_SUCCESS(Status
))
322 ExFreePool(ConnectData
);
329 * Reference the named port.
331 Status
= ObReferenceObjectByName (PortName
,
334 PORT_ALL_ACCESS
, /* DesiredAccess */
339 if (!NT_SUCCESS(Status
))
341 if (KeGetPreviousMode() != KernelMode
)
343 ExFreePool(ConnectData
);
349 * Reference the send section object.
351 if (WriteMap
.SectionHandle
!= INVALID_HANDLE_VALUE
)
353 Status
= ObReferenceObjectByHandle(WriteMap
.SectionHandle
,
354 SECTION_MAP_READ
| SECTION_MAP_WRITE
,
357 (PVOID
*)&SectionObject
,
359 if (!NT_SUCCESS(Status
))
361 ObDereferenceObject(NamedPort
);
362 if (KeGetPreviousMode() != KernelMode
)
364 ExFreePool(ConnectData
);
371 SectionObject
= NULL
;
375 * Do the connection establishment.
377 Status
= EiConnectPort(&ConnectedPort
,
383 &WriteMap
.TargetViewBase
,
389 if (!NT_SUCCESS(Status
))
391 /* FIXME: Again, check what NT does here. */
392 if (UnsafeConnectDataLength
!= NULL
)
394 if (ExGetPreviousMode() != KernelMode
)
396 MmCopyToCaller(UnsafeConnectData
,
399 ExFreePool(ConnectData
);
401 MmCopyToCaller(UnsafeConnectDataLength
,
409 * Do some initial cleanup.
411 if (SectionObject
!= NULL
)
413 ObDereferenceObject(SectionObject
);
414 SectionObject
= NULL
;
416 ObDereferenceObject(NamedPort
);
420 * Copy the data back to the caller.
422 if (ExGetPreviousMode() != KernelMode
)
424 if (UnsafeConnectDataLength
!= NULL
)
426 Status
= MmCopyToCaller(UnsafeConnectDataLength
,
429 if (!NT_SUCCESS(Status
))
434 if (UnsafeConnectData
!= NULL
&& ConnectData
!= NULL
)
436 Status
= MmCopyToCaller(UnsafeConnectData
,
439 ExFreePool(ConnectData
);
440 if (!NT_SUCCESS(Status
))
446 Status
= ObInsertObject(ConnectedPort
,
451 &ConnectedPortHandle
);
452 if (!NT_SUCCESS(Status
))
456 Status
= MmCopyToCaller(UnsafeConnectedPortHandle
,
457 &ConnectedPortHandle
,
459 if (!NT_SUCCESS(Status
))
463 if (UnsafeWriteMap
!= NULL
)
465 Status
= MmCopyToCaller(UnsafeWriteMap
,
467 sizeof(LPC_SECTION_WRITE
));
468 if (!NT_SUCCESS(Status
))
473 if (UnsafeReadMap
!= NULL
)
475 Status
= MmCopyToCaller(UnsafeReadMap
,
477 sizeof(LPC_SECTION_READ
));
478 if (!NT_SUCCESS(Status
))
483 if (UnsafeMaximumMessageSize
!= NULL
)
485 Status
= MmCopyToCaller(UnsafeMaximumMessageSize
,
488 if (!NT_SUCCESS(Status
))
498 return(STATUS_SUCCESS
);
502 /**********************************************************************
504 * NtAcceptConnectPort/6
518 /*EXPORTED*/ NTSTATUS STDCALL
519 NtAcceptConnectPort (PHANDLE ServerPortHandle
,
520 HANDLE NamedPortHandle
,
521 PLPC_MESSAGE LpcMessage
,
523 PLPC_SECTION_WRITE WriteMap
,
524 PLPC_SECTION_READ ReadMap
)
528 PEPORT OurPort
= NULL
;
529 PQUEUEDMESSAGE ConnectionRequest
;
531 PEPORT_CONNECT_REQUEST_MESSAGE CRequest
;
532 PEPORT_CONNECT_REPLY_MESSAGE CReply
;
535 Size
= sizeof(EPORT_CONNECT_REPLY_MESSAGE
);
538 Size
+= LpcMessage
->DataSize
;
541 CReply
= ExAllocatePool(NonPagedPool
, Size
);
544 return(STATUS_NO_MEMORY
);
547 Status
= ObReferenceObjectByHandle(NamedPortHandle
,
553 if (!NT_SUCCESS(Status
))
560 * Create a port object for our side of the connection
564 Status
= ObCreateObject(ExGetPreviousMode(),
573 if (!NT_SUCCESS(Status
))
576 ObDereferenceObject(NamedPort
);
580 Status
= ObInsertObject ((PVOID
)OurPort
,
586 if (!NT_SUCCESS(Status
))
588 ObDereferenceObject(OurPort
);
590 ObDereferenceObject(NamedPort
);
594 LpcpInitializePort(OurPort
, EPORT_TYPE_SERVER_COMM_PORT
, NamedPort
);
598 * Dequeue the connection request
600 KeAcquireSpinLock(&NamedPort
->Lock
, &oldIrql
);
601 ConnectionRequest
= EiDequeueConnectMessagePort (NamedPort
);
602 KeReleaseSpinLock(&NamedPort
->Lock
, oldIrql
);
603 CRequest
= (PEPORT_CONNECT_REQUEST_MESSAGE
)(&ConnectionRequest
->Message
);
608 if (LpcMessage
!= NULL
)
610 memcpy(&CReply
->MessageHeader
, LpcMessage
, sizeof(LPC_MESSAGE
));
611 memcpy(&CReply
->ConnectData
, (PVOID
)(LpcMessage
+ 1),
612 LpcMessage
->DataSize
);
613 CReply
->MessageHeader
.MessageSize
=
614 sizeof(EPORT_CONNECT_REPLY_MESSAGE
) + LpcMessage
->DataSize
;
615 CReply
->MessageHeader
.DataSize
= CReply
->MessageHeader
.MessageSize
-
617 CReply
->ConnectDataLength
= LpcMessage
->DataSize
;
621 CReply
->MessageHeader
.MessageSize
= sizeof(EPORT_CONNECT_REPLY_MESSAGE
);
622 CReply
->MessageHeader
.DataSize
= sizeof(EPORT_CONNECT_REPLY_MESSAGE
) -
624 CReply
->ConnectDataLength
= 0;
628 EiReplyOrRequestPort(ConnectionRequest
->Sender
,
629 &CReply
->MessageHeader
,
630 LPC_CONNECTION_REFUSED
,
632 KeReleaseSemaphore(&ConnectionRequest
->Sender
->Semaphore
,
636 ObDereferenceObject(ConnectionRequest
->Sender
);
637 ExFreePool(ConnectionRequest
);
639 ObDereferenceObject(NamedPort
);
640 return (STATUS_SUCCESS
);
644 * Prepare the connection.
646 if (WriteMap
!= NULL
)
648 PSECTION_OBJECT SectionObject
;
649 LARGE_INTEGER SectionOffset
;
651 Status
= ObReferenceObjectByHandle(WriteMap
->SectionHandle
,
652 SECTION_MAP_READ
| SECTION_MAP_WRITE
,
655 (PVOID
*)&SectionObject
,
657 if (!NT_SUCCESS(Status
))
662 SectionOffset
.QuadPart
= WriteMap
->SectionOffset
;
663 WriteMap
->TargetViewBase
= 0;
664 CReply
->ReceiveClientViewSize
= WriteMap
->ViewSize
;
665 Status
= MmMapViewOfSection(SectionObject
,
666 CRequest
->ConnectingProcess
,
667 &WriteMap
->TargetViewBase
,
669 CReply
->ReceiveClientViewSize
,
671 &CReply
->ReceiveClientViewSize
,
673 0 /* MEM_TOP_DOWN? */,
675 if (!NT_SUCCESS(Status
))
680 WriteMap
->ViewBase
= 0;
681 Status
= MmMapViewOfSection(SectionObject
,
682 PsGetCurrentProcess(),
689 0 /* MEM_TOP_DOWN? */,
691 if (!NT_SUCCESS(Status
))
696 ObDereferenceObject(SectionObject
);
698 if (ReadMap
!= NULL
&& CRequest
->SendSectionObject
!= NULL
)
700 LARGE_INTEGER SectionOffset
;
702 SectionOffset
= CRequest
->SendSectionOffset
;
703 ReadMap
->ViewSize
= CRequest
->SendViewSize
;
704 ReadMap
->ViewBase
= 0;
705 Status
= MmMapViewOfSection(CRequest
->SendSectionObject
,
706 PsGetCurrentProcess(),
709 CRequest
->SendViewSize
,
711 &CRequest
->SendViewSize
,
713 0 /* MEM_TOP_DOWN? */,
715 if (!NT_SUCCESS(Status
))
726 CReply
->SendServerViewBase
= ReadMap
->ViewBase
;
730 CReply
->SendServerViewBase
= 0;
732 if (WriteMap
!= NULL
)
734 CReply
->ReceiveClientViewBase
= WriteMap
->TargetViewBase
;
736 CReply
->MaximumMessageSize
= PORT_MAX_MESSAGE_LENGTH
;
740 * Connect the two ports
742 OurPort
->OtherPort
= ConnectionRequest
->Sender
;
743 OurPort
->OtherPort
->OtherPort
= OurPort
;
744 EiReplyOrRequestPort(ConnectionRequest
->Sender
,
745 (PLPC_MESSAGE
)CReply
,
748 ExFreePool(ConnectionRequest
);
751 ObDereferenceObject(OurPort
);
752 ObDereferenceObject(NamedPort
);
754 return (STATUS_SUCCESS
);
757 /**********************************************************************
759 * NtSecureConnectPort/9
762 * Connect to a named port and wait for the other side to
763 * accept the connection. Possibly verify that the server
764 * matches the ServerSid (trusted server).
769 * PortName: fully qualified name in the Ob name space;
776 * UserConnectInfoLength
781 NtSecureConnectPort (OUT PHANDLE ConnectedPort
,
782 IN PUNICODE_STRING PortName
,
783 IN PSECURITY_QUALITY_OF_SERVICE Qos
,
784 IN OUT PLPC_SECTION_WRITE WriteMap OPTIONAL
,
785 IN PSID ServerSid OPTIONAL
,
786 IN OUT PLPC_SECTION_READ ReadMap OPTIONAL
,
787 OUT PULONG MaxMessageSize OPTIONAL
,
788 IN OUT PVOID ConnectInfo OPTIONAL
,
789 IN OUT PULONG UserConnectInfoLength OPTIONAL
)
791 /* TODO: implement a new object type: WaitablePort */
792 /* TODO: verify the process' SID that hosts the rendez-vous port equals ServerSid */
793 return NtConnectPort (ConnectedPort
,
800 UserConnectInfoLength
);