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 /* FUNCTIONS *****************************************************************/
19 /**********************************************************************
30 EiConnectPort(IN PEPORT
* ConnectedPort
,
33 IN LARGE_INTEGER SectionOffset
,
35 OUT PVOID
* ClientSendViewBase
,
36 OUT PVOID
* ServerSendViewBase
,
37 OUT PULONG ReceiveViewSize
,
38 OUT PVOID
* ReceiveViewBase
,
39 OUT PULONG MaximumMessageSize
,
40 IN OUT PVOID ConnectData
,
41 IN OUT PULONG ConnectDataLength
)
43 PEPORT_CONNECT_REQUEST_MESSAGE RequestMessage
;
44 ULONG RequestConnectDataLength
;
47 PEPORT_CONNECT_REPLY_MESSAGE CReply
;
51 if (ConnectDataLength
== NULL
)
53 RequestConnectDataLength
= 0;
57 RequestConnectDataLength
= *ConnectDataLength
;
61 * Create a port to represent our side of the connection
63 Status
= ObCreateObject (KernelMode
,
72 if (!NT_SUCCESS(Status
))
76 LpcpInitializePort(OurPort
, EPORT_TYPE_CLIENT_COMM_PORT
, NamedPort
);
79 * Allocate a request message.
81 RequestMessage
= ExAllocatePool(NonPagedPool
,
82 sizeof(EPORT_CONNECT_REQUEST_MESSAGE
) +
83 RequestConnectDataLength
);
84 if (RequestMessage
== NULL
)
86 ObDereferenceObject(OurPort
);
87 return(STATUS_NO_MEMORY
);
91 * Initialize the request message.
93 RequestMessage
->MessageHeader
.u1
.s1
.DataLength
=
94 sizeof(EPORT_CONNECT_REQUEST_MESSAGE
) + RequestConnectDataLength
-
96 RequestMessage
->MessageHeader
.u1
.s1
.TotalLength
=
97 sizeof(EPORT_CONNECT_REQUEST_MESSAGE
) + RequestConnectDataLength
;
98 DPRINT("RequestMessageSize %d\n",
99 RequestMessage
->MessageHeader
.u1
.s1
.TotalLength
);
100 RequestMessage
->MessageHeader
.ClientViewSize
= 0;
101 RequestMessage
->ConnectingProcess
= PsGetCurrentProcess();
102 ObReferenceObjectByPointer(RequestMessage
->ConnectingProcess
,
103 PROCESS_VM_OPERATION
,
106 RequestMessage
->SendSectionObject
= (struct _SECTION_OBJECT
*)Section
;
107 RequestMessage
->SendSectionOffset
= SectionOffset
;
108 RequestMessage
->SendViewSize
= ViewSize
;
109 RequestMessage
->ConnectDataLength
= RequestConnectDataLength
;
110 if (RequestConnectDataLength
> 0)
112 memcpy(RequestMessage
->ConnectData
, ConnectData
,
113 RequestConnectDataLength
);
117 * Queue the message to the named port
119 EiReplyOrRequestPort(NamedPort
,
120 &RequestMessage
->MessageHeader
,
121 LPC_CONNECTION_REQUEST
,
123 KeReleaseSemaphore(&NamedPort
->Semaphore
, IO_NO_INCREMENT
, 1, FALSE
);
124 ExFreePool(RequestMessage
);
127 * Wait for them to accept our connection
129 KeWaitForSingleObject(&OurPort
->Semaphore
,
136 * Dequeue the response
138 KeAcquireSpinLock (&OurPort
->Lock
, &oldIrql
);
139 Reply
= EiDequeueMessagePort (OurPort
);
140 KeReleaseSpinLock (&OurPort
->Lock
, oldIrql
);
141 CReply
= (PEPORT_CONNECT_REPLY_MESSAGE
)&Reply
->Message
;
144 * Do some initial cleanup.
146 ObDereferenceObject(PsGetCurrentProcess());
149 * Check for connection refusal.
151 if (CReply
->MessageHeader
.u2
.s2
.Type
== LPC_CONNECTION_REFUSED
)
153 ObDereferenceObject(OurPort
);
156 * FIXME: Check what NT does here. Giving the user data back on
157 * connect failure sounds reasonable; it probably wouldn't break
160 if (ConnectDataLength
!= NULL
)
162 *ConnectDataLength
= CReply
->ConnectDataLength
;
163 memcpy(ConnectData
, CReply
->ConnectData
, CReply
->ConnectDataLength
);
165 return(STATUS_PORT_CONNECTION_REFUSED
);
169 * Otherwise we are connected. Copy data back to the client.
171 *ServerSendViewBase
= CReply
->SendServerViewBase
;
172 *ReceiveViewSize
= CReply
->ReceiveClientViewSize
;
173 *ReceiveViewBase
= CReply
->ReceiveClientViewBase
;
174 *MaximumMessageSize
= CReply
->MaximumMessageSize
;
175 if (ConnectDataLength
!= NULL
)
177 *ConnectDataLength
= CReply
->ConnectDataLength
;
178 memcpy(ConnectData
, CReply
->ConnectData
, CReply
->ConnectDataLength
);
182 * Create our view of the send section object.
186 *ClientSendViewBase
= 0;
187 Status
= MmMapViewOfSection(Section
,
188 PsGetCurrentProcess(),
195 0 /* MEM_TOP_DOWN? */,
197 if (!NT_SUCCESS(Status
))
199 /* FIXME: Cleanup here. */
205 * Do the final initialization of our port.
207 OurPort
->State
= EPORT_CONNECTED_CLIENT
;
213 *ConnectedPort
= OurPort
;
214 return(STATUS_SUCCESS
);
217 /**********************************************************************
222 * Connect to a named port and wait for the other side to
223 * accept or reject the connection request.
233 * UserConnectInfoLength
240 NtConnectPort (PHANDLE UnsafeConnectedPortHandle
,
241 PUNICODE_STRING PortName
,
242 PSECURITY_QUALITY_OF_SERVICE Qos
,
243 PPORT_VIEW UnsafeWriteMap
,
244 PREMOTE_PORT_VIEW UnsafeReadMap
,
245 PULONG UnsafeMaximumMessageSize
,
246 PVOID UnsafeConnectData
,
247 PULONG UnsafeConnectDataLength
)
249 HANDLE ConnectedPortHandle
;
251 REMOTE_PORT_VIEW ReadMap
;
252 ULONG MaximumMessageSize
;
253 PVOID ConnectData
= NULL
;
254 ULONG ConnectDataLength
= 0;
256 LARGE_INTEGER SectionOffset
;
257 PEPORT ConnectedPort
;
258 KPROCESSOR_MODE PreviousMode
;
259 NTSTATUS Status
= STATUS_SUCCESS
;
262 PreviousMode
= ExGetPreviousMode();
264 if (PreviousMode
!= KernelMode
)
268 ProbeForWriteHandle(UnsafeConnectedPortHandle
);
269 if (UnsafeMaximumMessageSize
!= NULL
)
271 ProbeForWriteUlong(UnsafeMaximumMessageSize
);
276 Status
= _SEH_GetExceptionCode();
280 if (!NT_SUCCESS(Status
))
287 * Copy in write map and partially validate.
289 if (UnsafeWriteMap
!= NULL
)
291 if (PreviousMode
!= KernelMode
)
295 ProbeForWrite(UnsafeWriteMap
,
298 RtlCopyMemory(&WriteMap
,
304 Status
= _SEH_GetExceptionCode();
308 if (!NT_SUCCESS(Status
))
315 RtlCopyMemory(&WriteMap
,
320 if (WriteMap
.Length
!= sizeof(PORT_VIEW
))
322 return(STATUS_INVALID_PARAMETER_4
);
324 SectionOffset
.QuadPart
= WriteMap
.SectionOffset
;
328 WriteMap
.SectionHandle
= INVALID_HANDLE_VALUE
;
332 * Handle connection data.
334 if (UnsafeConnectData
)
336 if (PreviousMode
!= KernelMode
)
340 ConnectDataLength
= ProbeForReadUlong(UnsafeConnectDataLength
);
344 Status
= _SEH_GetExceptionCode();
348 if (!NT_SUCCESS(Status
))
355 ConnectDataLength
= *UnsafeConnectDataLength
;
358 if (ConnectDataLength
!= 0)
360 ConnectData
= ExAllocatePool(NonPagedPool
, ConnectDataLength
);
361 if (ConnectData
== NULL
)
363 return(STATUS_NO_MEMORY
);
366 if (PreviousMode
!= KernelMode
)
370 ProbeForWriteUlong(UnsafeConnectData
);
371 RtlCopyMemory(ConnectData
,
377 Status
= _SEH_GetExceptionCode();
381 if (!NT_SUCCESS(Status
))
383 ExFreePool(ConnectData
);
389 RtlCopyMemory(ConnectData
,
397 * Reference the named port.
399 Status
= ObReferenceObjectByName (PortName
,
402 PORT_ALL_ACCESS
, /* DesiredAccess */
407 if (!NT_SUCCESS(Status
))
409 if (KeGetPreviousMode() != KernelMode
)
411 ExFreePool(ConnectData
);
417 * Reference the send section object.
419 if (WriteMap
.SectionHandle
!= INVALID_HANDLE_VALUE
)
421 Status
= ObReferenceObjectByHandle(WriteMap
.SectionHandle
,
422 SECTION_MAP_READ
| SECTION_MAP_WRITE
,
425 (PVOID
*)&SectionObject
,
427 if (!NT_SUCCESS(Status
))
429 ObDereferenceObject(NamedPort
);
430 if (KeGetPreviousMode() != KernelMode
)
432 ExFreePool(ConnectData
);
439 SectionObject
= NULL
;
443 * Do the connection establishment.
445 Status
= EiConnectPort(&ConnectedPort
,
451 &WriteMap
.ViewRemoteBase
,
457 if (!NT_SUCCESS(Status
))
459 /* FIXME: Again, check what NT does here. */
460 if (UnsafeConnectDataLength
!= NULL
)
462 if (PreviousMode
!= KernelMode
)
466 RtlCopyMemory(UnsafeConnectData
,
469 *UnsafeConnectDataLength
= ConnectDataLength
;
473 Status
= _SEH_GetExceptionCode();
479 RtlCopyMemory(UnsafeConnectData
,
482 *UnsafeConnectDataLength
= ConnectDataLength
;
485 ExFreePool(ConnectData
);
491 * Do some initial cleanup.
493 if (SectionObject
!= NULL
)
495 ObDereferenceObject(SectionObject
);
496 SectionObject
= NULL
;
498 ObDereferenceObject(NamedPort
);
502 * Copy the data back to the caller.
505 if (UnsafeConnectDataLength
!= NULL
)
507 if (PreviousMode
!= KernelMode
)
511 *UnsafeConnectDataLength
= ConnectDataLength
;
513 if (ConnectData
!= NULL
)
515 RtlCopyMemory(UnsafeConnectData
,
522 Status
= _SEH_GetExceptionCode();
526 if (!NT_SUCCESS(Status
))
528 if (ConnectData
!= NULL
)
530 ExFreePool(ConnectData
);
537 *UnsafeConnectDataLength
= ConnectDataLength
;
539 if (ConnectData
!= NULL
)
541 RtlCopyMemory(UnsafeConnectData
,
547 if (ConnectData
!= NULL
)
549 ExFreePool(ConnectData
);
552 Status
= ObInsertObject(ConnectedPort
,
556 (PVOID
*)&ConnectedPort
,
557 &ConnectedPortHandle
);
558 if (!NT_SUCCESS(Status
))
563 if (PreviousMode
!= KernelMode
)
567 *UnsafeConnectedPortHandle
= ConnectedPortHandle
;
569 if (UnsafeWriteMap
!= NULL
)
571 RtlCopyMemory(UnsafeWriteMap
,
576 if (UnsafeReadMap
!= NULL
)
578 RtlCopyMemory(UnsafeReadMap
,
580 sizeof(REMOTE_PORT_VIEW
));
583 if (UnsafeMaximumMessageSize
!= NULL
)
585 *UnsafeMaximumMessageSize
= MaximumMessageSize
;
590 Status
= _SEH_GetExceptionCode();
594 if (!NT_SUCCESS(Status
))
601 *UnsafeConnectedPortHandle
= ConnectedPortHandle
;
603 if (UnsafeWriteMap
!= NULL
)
605 RtlCopyMemory(UnsafeWriteMap
,
610 if (UnsafeReadMap
!= NULL
)
612 RtlCopyMemory(UnsafeReadMap
,
614 sizeof(REMOTE_PORT_VIEW
));
617 if (UnsafeMaximumMessageSize
!= NULL
)
619 *UnsafeMaximumMessageSize
= MaximumMessageSize
;
627 return(STATUS_SUCCESS
);
631 /**********************************************************************
633 * NtAcceptConnectPort/6
647 /*EXPORTED*/ NTSTATUS STDCALL
648 NtAcceptConnectPort (PHANDLE ServerPortHandle
,
649 HANDLE NamedPortHandle
,
650 PPORT_MESSAGE LpcMessage
,
653 PREMOTE_PORT_VIEW ReadMap
)
657 PEPORT OurPort
= NULL
;
658 PQUEUEDMESSAGE ConnectionRequest
;
660 PEPORT_CONNECT_REQUEST_MESSAGE CRequest
;
661 PEPORT_CONNECT_REPLY_MESSAGE CReply
;
663 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
665 Size
= sizeof(EPORT_CONNECT_REPLY_MESSAGE
);
668 Size
+= LpcMessage
->u1
.s1
.DataLength
;
671 CReply
= ExAllocatePool(NonPagedPool
, Size
);
674 return(STATUS_NO_MEMORY
);
677 Status
= ObReferenceObjectByHandle(NamedPortHandle
,
683 if (!NT_SUCCESS(Status
))
690 * Create a port object for our side of the connection
694 Status
= ObCreateObject(PreviousMode
,
703 if (!NT_SUCCESS(Status
))
706 ObDereferenceObject(NamedPort
);
710 Status
= ObInsertObject ((PVOID
)OurPort
,
716 if (!NT_SUCCESS(Status
))
718 ObDereferenceObject(OurPort
);
720 ObDereferenceObject(NamedPort
);
724 LpcpInitializePort(OurPort
, EPORT_TYPE_SERVER_COMM_PORT
, NamedPort
);
728 * Dequeue the connection request
730 KeAcquireSpinLock(&NamedPort
->Lock
, &oldIrql
);
731 ConnectionRequest
= EiDequeueConnectMessagePort (NamedPort
);
732 KeReleaseSpinLock(&NamedPort
->Lock
, oldIrql
);
733 CRequest
= (PEPORT_CONNECT_REQUEST_MESSAGE
)(&ConnectionRequest
->Message
);
738 if (LpcMessage
!= NULL
)
740 memcpy(&CReply
->MessageHeader
, LpcMessage
, sizeof(PORT_MESSAGE
));
741 memcpy(&CReply
->ConnectData
, (PVOID
)(LpcMessage
+ 1),
742 LpcMessage
->u1
.s1
.DataLength
);
743 CReply
->MessageHeader
.u1
.s1
.TotalLength
=
744 sizeof(EPORT_CONNECT_REPLY_MESSAGE
) + LpcMessage
->u1
.s1
.DataLength
;
745 CReply
->MessageHeader
.u1
.s1
.DataLength
= CReply
->MessageHeader
.u1
.s1
.TotalLength
-
746 sizeof(PORT_MESSAGE
);
747 CReply
->ConnectDataLength
= LpcMessage
->u1
.s1
.DataLength
;
751 CReply
->MessageHeader
.u1
.s1
.TotalLength
= sizeof(EPORT_CONNECT_REPLY_MESSAGE
);
752 CReply
->MessageHeader
.u1
.s1
.DataLength
= sizeof(EPORT_CONNECT_REPLY_MESSAGE
) -
753 sizeof(PORT_MESSAGE
);
754 CReply
->ConnectDataLength
= 0;
758 EiReplyOrRequestPort(ConnectionRequest
->Sender
,
759 &CReply
->MessageHeader
,
760 LPC_CONNECTION_REFUSED
,
762 KeReleaseSemaphore(&ConnectionRequest
->Sender
->Semaphore
,
766 ObDereferenceObject(ConnectionRequest
->Sender
);
767 ExFreePool(ConnectionRequest
);
769 ObDereferenceObject(NamedPort
);
770 return (STATUS_SUCCESS
);
774 * Prepare the connection.
776 if (WriteMap
!= NULL
)
779 LARGE_INTEGER SectionOffset
;
781 Status
= ObReferenceObjectByHandle(WriteMap
->SectionHandle
,
782 SECTION_MAP_READ
| SECTION_MAP_WRITE
,
785 (PVOID
*)&SectionObject
,
787 if (!NT_SUCCESS(Status
))
792 SectionOffset
.QuadPart
= WriteMap
->SectionOffset
;
793 WriteMap
->ViewRemoteBase
= 0;
794 CReply
->ReceiveClientViewSize
= WriteMap
->ViewSize
;
795 Status
= MmMapViewOfSection(SectionObject
,
796 CRequest
->ConnectingProcess
,
797 &WriteMap
->ViewRemoteBase
,
799 CReply
->ReceiveClientViewSize
,
801 &CReply
->ReceiveClientViewSize
,
803 0 /* MEM_TOP_DOWN? */,
805 if (!NT_SUCCESS(Status
))
810 WriteMap
->ViewBase
= 0;
811 Status
= MmMapViewOfSection(SectionObject
,
812 PsGetCurrentProcess(),
819 0 /* MEM_TOP_DOWN? */,
821 if (!NT_SUCCESS(Status
))
826 ObDereferenceObject(SectionObject
);
828 if (ReadMap
!= NULL
&& CRequest
->SendSectionObject
!= NULL
)
830 LARGE_INTEGER SectionOffset
;
832 SectionOffset
= CRequest
->SendSectionOffset
;
833 ReadMap
->ViewSize
= CRequest
->SendViewSize
;
834 ReadMap
->ViewBase
= 0;
835 Status
= MmMapViewOfSection(CRequest
->SendSectionObject
,
836 PsGetCurrentProcess(),
839 CRequest
->SendViewSize
,
841 &CRequest
->SendViewSize
,
843 0 /* MEM_TOP_DOWN? */,
845 if (!NT_SUCCESS(Status
))
856 CReply
->SendServerViewBase
= ReadMap
->ViewBase
;
860 CReply
->SendServerViewBase
= 0;
862 if (WriteMap
!= NULL
)
864 CReply
->ReceiveClientViewBase
= WriteMap
->ViewRemoteBase
;
866 CReply
->MaximumMessageSize
= LPC_MAX_MESSAGE_LENGTH
;
870 * Connect the two ports
872 OurPort
->OtherPort
= ConnectionRequest
->Sender
;
873 OurPort
->OtherPort
->OtherPort
= OurPort
;
874 EiReplyOrRequestPort(ConnectionRequest
->Sender
,
875 (PPORT_MESSAGE
)CReply
,
878 ExFreePool(ConnectionRequest
);
881 //ObDereferenceObject(OurPort);
882 ObDereferenceObject(NamedPort
);
884 return (STATUS_SUCCESS
);
887 /**********************************************************************
889 * NtSecureConnectPort/9
892 * Connect to a named port and wait for the other side to
893 * accept the connection. Possibly verify that the server
894 * matches the ServerSid (trusted server).
899 * PortName: fully qualified name in the Ob name space;
906 * UserConnectInfoLength
911 NtSecureConnectPort (OUT PHANDLE ConnectedPort
,
912 IN PUNICODE_STRING PortName
,
913 IN PSECURITY_QUALITY_OF_SERVICE Qos
,
914 IN OUT PPORT_VIEW WriteMap OPTIONAL
,
915 IN PSID ServerSid OPTIONAL
,
916 IN OUT PREMOTE_PORT_VIEW ReadMap OPTIONAL
,
917 OUT PULONG MaxMessageSize OPTIONAL
,
918 IN OUT PVOID ConnectInfo OPTIONAL
,
919 IN OUT PULONG UserConnectInfoLength OPTIONAL
)
921 /* TODO: implement a new object type: WaitablePort */
922 /* TODO: verify the process' SID that hosts the rendez-vous port equals ServerSid */
923 return NtConnectPort (ConnectedPort
,
930 UserConnectInfoLength
);