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
,
32 IN PSECTION_OBJECT Section
,
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 PLPC_SECTION_WRITE UnsafeWriteMap
,
244 PLPC_SECTION_READ UnsafeReadMap
,
245 PULONG UnsafeMaximumMessageSize
,
246 PVOID UnsafeConnectData
,
247 PULONG UnsafeConnectDataLength
)
249 HANDLE ConnectedPortHandle
;
250 LPC_SECTION_WRITE WriteMap
;
251 LPC_SECTION_READ ReadMap
;
252 ULONG MaximumMessageSize
;
253 PVOID ConnectData
= NULL
;
254 ULONG ConnectDataLength
= 0;
255 PSECTION_OBJECT SectionObject
;
256 LARGE_INTEGER SectionOffset
;
257 PEPORT ConnectedPort
;
258 KPROCESSOR_MODE PreviousMode
;
259 NTSTATUS Status
= STATUS_SUCCESS
;
262 PreviousMode
= ExGetPreviousMode();
264 if (PreviousMode
!= KernelMode
)
268 ProbeForWrite(UnsafeConnectedPortHandle
,
271 if (UnsafeMaximumMessageSize
!= NULL
)
273 ProbeForWrite(UnsafeMaximumMessageSize
,
280 Status
= _SEH_GetExceptionCode();
284 if (!NT_SUCCESS(Status
))
291 * Copy in write map and partially validate.
293 if (UnsafeWriteMap
!= NULL
)
295 if (PreviousMode
!= KernelMode
)
299 ProbeForWrite(UnsafeWriteMap
,
300 sizeof(LPC_SECTION_WRITE
),
302 RtlCopyMemory(&WriteMap
,
304 sizeof(LPC_SECTION_WRITE
));
308 Status
= _SEH_GetExceptionCode();
312 if (!NT_SUCCESS(Status
))
319 RtlCopyMemory(&WriteMap
,
321 sizeof(LPC_SECTION_WRITE
));
324 if (WriteMap
.Length
!= sizeof(LPC_SECTION_WRITE
))
326 return(STATUS_INVALID_PARAMETER_4
);
328 SectionOffset
.QuadPart
= WriteMap
.SectionOffset
;
332 WriteMap
.SectionHandle
= INVALID_HANDLE_VALUE
;
336 * Handle connection data.
338 if (UnsafeConnectData
)
340 if (PreviousMode
!= KernelMode
)
344 ProbeForRead(UnsafeConnectDataLength
,
347 ConnectDataLength
= *UnsafeConnectDataLength
;
351 Status
= _SEH_GetExceptionCode();
355 if (!NT_SUCCESS(Status
))
362 ConnectDataLength
= *UnsafeConnectDataLength
;
365 if (ConnectDataLength
!= 0)
367 ConnectData
= ExAllocatePool(NonPagedPool
, ConnectDataLength
);
368 if (ConnectData
== NULL
)
370 return(STATUS_NO_MEMORY
);
373 if (PreviousMode
!= KernelMode
)
377 ProbeForWrite(UnsafeConnectData
,
380 RtlCopyMemory(ConnectData
,
386 Status
= _SEH_GetExceptionCode();
390 if (!NT_SUCCESS(Status
))
392 ExFreePool(ConnectData
);
398 RtlCopyMemory(ConnectData
,
406 * Reference the named port.
408 Status
= ObReferenceObjectByName (PortName
,
411 PORT_ALL_ACCESS
, /* DesiredAccess */
416 if (!NT_SUCCESS(Status
))
418 if (KeGetPreviousMode() != KernelMode
)
420 ExFreePool(ConnectData
);
426 * Reference the send section object.
428 if (WriteMap
.SectionHandle
!= INVALID_HANDLE_VALUE
)
430 Status
= ObReferenceObjectByHandle(WriteMap
.SectionHandle
,
431 SECTION_MAP_READ
| SECTION_MAP_WRITE
,
434 (PVOID
*)&SectionObject
,
436 if (!NT_SUCCESS(Status
))
438 ObDereferenceObject(NamedPort
);
439 if (KeGetPreviousMode() != KernelMode
)
441 ExFreePool(ConnectData
);
448 SectionObject
= NULL
;
452 * Do the connection establishment.
454 Status
= EiConnectPort(&ConnectedPort
,
460 &WriteMap
.TargetViewBase
,
466 if (!NT_SUCCESS(Status
))
468 /* FIXME: Again, check what NT does here. */
469 if (UnsafeConnectDataLength
!= NULL
)
471 if (PreviousMode
!= KernelMode
)
475 RtlCopyMemory(UnsafeConnectData
,
478 *UnsafeConnectDataLength
= ConnectDataLength
;
482 Status
= _SEH_GetExceptionCode();
488 RtlCopyMemory(UnsafeConnectData
,
491 *UnsafeConnectDataLength
= ConnectDataLength
;
494 ExFreePool(ConnectData
);
500 * Do some initial cleanup.
502 if (SectionObject
!= NULL
)
504 ObDereferenceObject(SectionObject
);
505 SectionObject
= NULL
;
507 ObDereferenceObject(NamedPort
);
511 * Copy the data back to the caller.
514 if (UnsafeConnectDataLength
!= NULL
)
516 if (PreviousMode
!= KernelMode
)
520 *UnsafeConnectDataLength
= ConnectDataLength
;
522 if (ConnectData
!= NULL
)
524 RtlCopyMemory(UnsafeConnectData
,
531 Status
= _SEH_GetExceptionCode();
535 if (!NT_SUCCESS(Status
))
537 if (ConnectData
!= NULL
)
539 ExFreePool(ConnectData
);
546 *UnsafeConnectDataLength
= ConnectDataLength
;
548 if (ConnectData
!= NULL
)
550 RtlCopyMemory(UnsafeConnectData
,
556 if (ConnectData
!= NULL
)
558 ExFreePool(ConnectData
);
561 Status
= ObInsertObject(ConnectedPort
,
566 &ConnectedPortHandle
);
567 if (!NT_SUCCESS(Status
))
572 if (PreviousMode
!= KernelMode
)
576 *UnsafeConnectedPortHandle
= ConnectedPortHandle
;
578 if (UnsafeWriteMap
!= NULL
)
580 RtlCopyMemory(UnsafeWriteMap
,
582 sizeof(LPC_SECTION_WRITE
));
585 if (UnsafeReadMap
!= NULL
)
587 RtlCopyMemory(UnsafeReadMap
,
589 sizeof(LPC_SECTION_READ
));
592 if (UnsafeMaximumMessageSize
!= NULL
)
594 *UnsafeMaximumMessageSize
= MaximumMessageSize
;
599 Status
= _SEH_GetExceptionCode();
603 if (!NT_SUCCESS(Status
))
610 *UnsafeConnectedPortHandle
= ConnectedPortHandle
;
612 if (UnsafeWriteMap
!= NULL
)
614 RtlCopyMemory(UnsafeWriteMap
,
616 sizeof(LPC_SECTION_WRITE
));
619 if (UnsafeReadMap
!= NULL
)
621 RtlCopyMemory(UnsafeReadMap
,
623 sizeof(LPC_SECTION_READ
));
626 if (UnsafeMaximumMessageSize
!= NULL
)
628 *UnsafeMaximumMessageSize
= MaximumMessageSize
;
636 return(STATUS_SUCCESS
);
640 /**********************************************************************
642 * NtAcceptConnectPort/6
656 /*EXPORTED*/ NTSTATUS STDCALL
657 NtAcceptConnectPort (PHANDLE ServerPortHandle
,
658 HANDLE NamedPortHandle
,
659 PPORT_MESSAGE LpcMessage
,
661 PLPC_SECTION_WRITE WriteMap
,
662 PLPC_SECTION_READ ReadMap
)
666 PEPORT OurPort
= NULL
;
667 PQUEUEDMESSAGE ConnectionRequest
;
669 PEPORT_CONNECT_REQUEST_MESSAGE CRequest
;
670 PEPORT_CONNECT_REPLY_MESSAGE CReply
;
672 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
674 Size
= sizeof(EPORT_CONNECT_REPLY_MESSAGE
);
677 Size
+= LpcMessage
->u1
.s1
.DataLength
;
680 CReply
= ExAllocatePool(NonPagedPool
, Size
);
683 return(STATUS_NO_MEMORY
);
686 Status
= ObReferenceObjectByHandle(NamedPortHandle
,
692 if (!NT_SUCCESS(Status
))
699 * Create a port object for our side of the connection
703 Status
= ObCreateObject(PreviousMode
,
712 if (!NT_SUCCESS(Status
))
715 ObDereferenceObject(NamedPort
);
719 Status
= ObInsertObject ((PVOID
)OurPort
,
725 if (!NT_SUCCESS(Status
))
727 ObDereferenceObject(OurPort
);
729 ObDereferenceObject(NamedPort
);
733 LpcpInitializePort(OurPort
, EPORT_TYPE_SERVER_COMM_PORT
, NamedPort
);
737 * Dequeue the connection request
739 KeAcquireSpinLock(&NamedPort
->Lock
, &oldIrql
);
740 ConnectionRequest
= EiDequeueConnectMessagePort (NamedPort
);
741 KeReleaseSpinLock(&NamedPort
->Lock
, oldIrql
);
742 CRequest
= (PEPORT_CONNECT_REQUEST_MESSAGE
)(&ConnectionRequest
->Message
);
747 if (LpcMessage
!= NULL
)
749 memcpy(&CReply
->MessageHeader
, LpcMessage
, sizeof(PORT_MESSAGE
));
750 memcpy(&CReply
->ConnectData
, (PVOID
)(LpcMessage
+ 1),
751 LpcMessage
->u1
.s1
.DataLength
);
752 CReply
->MessageHeader
.u1
.s1
.TotalLength
=
753 sizeof(EPORT_CONNECT_REPLY_MESSAGE
) + LpcMessage
->u1
.s1
.DataLength
;
754 CReply
->MessageHeader
.u1
.s1
.DataLength
= CReply
->MessageHeader
.u1
.s1
.TotalLength
-
755 sizeof(PORT_MESSAGE
);
756 CReply
->ConnectDataLength
= LpcMessage
->u1
.s1
.DataLength
;
760 CReply
->MessageHeader
.u1
.s1
.TotalLength
= sizeof(EPORT_CONNECT_REPLY_MESSAGE
);
761 CReply
->MessageHeader
.u1
.s1
.DataLength
= sizeof(EPORT_CONNECT_REPLY_MESSAGE
) -
762 sizeof(PORT_MESSAGE
);
763 CReply
->ConnectDataLength
= 0;
767 EiReplyOrRequestPort(ConnectionRequest
->Sender
,
768 &CReply
->MessageHeader
,
769 LPC_CONNECTION_REFUSED
,
771 KeReleaseSemaphore(&ConnectionRequest
->Sender
->Semaphore
,
775 ObDereferenceObject(ConnectionRequest
->Sender
);
776 ExFreePool(ConnectionRequest
);
778 ObDereferenceObject(NamedPort
);
779 return (STATUS_SUCCESS
);
783 * Prepare the connection.
785 if (WriteMap
!= NULL
)
787 PSECTION_OBJECT SectionObject
;
788 LARGE_INTEGER SectionOffset
;
790 Status
= ObReferenceObjectByHandle(WriteMap
->SectionHandle
,
791 SECTION_MAP_READ
| SECTION_MAP_WRITE
,
794 (PVOID
*)&SectionObject
,
796 if (!NT_SUCCESS(Status
))
801 SectionOffset
.QuadPart
= WriteMap
->SectionOffset
;
802 WriteMap
->TargetViewBase
= 0;
803 CReply
->ReceiveClientViewSize
= WriteMap
->ViewSize
;
804 Status
= MmMapViewOfSection(SectionObject
,
805 CRequest
->ConnectingProcess
,
806 &WriteMap
->TargetViewBase
,
808 CReply
->ReceiveClientViewSize
,
810 &CReply
->ReceiveClientViewSize
,
812 0 /* MEM_TOP_DOWN? */,
814 if (!NT_SUCCESS(Status
))
819 WriteMap
->ViewBase
= 0;
820 Status
= MmMapViewOfSection(SectionObject
,
821 PsGetCurrentProcess(),
828 0 /* MEM_TOP_DOWN? */,
830 if (!NT_SUCCESS(Status
))
835 ObDereferenceObject(SectionObject
);
837 if (ReadMap
!= NULL
&& CRequest
->SendSectionObject
!= NULL
)
839 LARGE_INTEGER SectionOffset
;
841 SectionOffset
= CRequest
->SendSectionOffset
;
842 ReadMap
->ViewSize
= CRequest
->SendViewSize
;
843 ReadMap
->ViewBase
= 0;
844 Status
= MmMapViewOfSection(CRequest
->SendSectionObject
,
845 PsGetCurrentProcess(),
848 CRequest
->SendViewSize
,
850 &CRequest
->SendViewSize
,
852 0 /* MEM_TOP_DOWN? */,
854 if (!NT_SUCCESS(Status
))
865 CReply
->SendServerViewBase
= ReadMap
->ViewBase
;
869 CReply
->SendServerViewBase
= 0;
871 if (WriteMap
!= NULL
)
873 CReply
->ReceiveClientViewBase
= WriteMap
->TargetViewBase
;
875 CReply
->MaximumMessageSize
= LPC_MAX_MESSAGE_LENGTH
;
879 * Connect the two ports
881 OurPort
->OtherPort
= ConnectionRequest
->Sender
;
882 OurPort
->OtherPort
->OtherPort
= OurPort
;
883 EiReplyOrRequestPort(ConnectionRequest
->Sender
,
884 (PPORT_MESSAGE
)CReply
,
887 ExFreePool(ConnectionRequest
);
890 ObDereferenceObject(OurPort
);
891 ObDereferenceObject(NamedPort
);
893 return (STATUS_SUCCESS
);
896 /**********************************************************************
898 * NtSecureConnectPort/9
901 * Connect to a named port and wait for the other side to
902 * accept the connection. Possibly verify that the server
903 * matches the ServerSid (trusted server).
908 * PortName: fully qualified name in the Ob name space;
915 * UserConnectInfoLength
920 NtSecureConnectPort (OUT PHANDLE ConnectedPort
,
921 IN PUNICODE_STRING PortName
,
922 IN PSECURITY_QUALITY_OF_SERVICE Qos
,
923 IN OUT PLPC_SECTION_WRITE WriteMap OPTIONAL
,
924 IN PSID ServerSid OPTIONAL
,
925 IN OUT PLPC_SECTION_READ ReadMap OPTIONAL
,
926 OUT PULONG MaxMessageSize OPTIONAL
,
927 IN OUT PVOID ConnectInfo OPTIONAL
,
928 IN OUT PULONG UserConnectInfoLength OPTIONAL
)
930 /* TODO: implement a new object type: WaitablePort */
931 /* TODO: verify the process' SID that hosts the rendez-vous port equals ServerSid */
932 return NtConnectPort (ConnectedPort
,
939 UserConnectInfoLength
);