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
.DataSize
=
94 sizeof(EPORT_CONNECT_REQUEST_MESSAGE
) + RequestConnectDataLength
-
96 RequestMessage
->MessageHeader
.MessageSize
=
97 sizeof(EPORT_CONNECT_REQUEST_MESSAGE
) + RequestConnectDataLength
;
98 DPRINT("RequestMessageSize %d\n",
99 RequestMessage
->MessageHeader
.MessageSize
);
100 RequestMessage
->MessageHeader
.SectionSize
= 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
.MessageType
== 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
;
254 ULONG ConnectDataLength
;
255 PSECTION_OBJECT SectionObject
;
256 LARGE_INTEGER SectionOffset
;
257 PEPORT ConnectedPort
;
262 * Copy in write map and partially validate.
264 if (UnsafeWriteMap
!= NULL
)
266 Status
= MmCopyFromCaller(&WriteMap
,
268 sizeof(LPC_SECTION_WRITE
));
269 if (!NT_SUCCESS(Status
))
273 if (WriteMap
.Length
!= sizeof(LPC_SECTION_WRITE
))
275 return(STATUS_INVALID_PARAMETER_4
);
277 SectionOffset
.QuadPart
= WriteMap
.SectionOffset
;
281 WriteMap
.SectionHandle
= INVALID_HANDLE_VALUE
;
285 * Handle connection data.
287 if (UnsafeConnectData
== NULL
)
289 ConnectDataLength
= 0;
294 if (ExGetPreviousMode() == KernelMode
)
296 ConnectDataLength
= *UnsafeConnectDataLength
;
297 ConnectData
= UnsafeConnectData
;
301 Status
= MmCopyFromCaller(&ConnectDataLength
,
302 UnsafeConnectDataLength
,
304 if (!NT_SUCCESS(Status
))
308 ConnectData
= ExAllocatePool(NonPagedPool
, ConnectDataLength
);
309 if (ConnectData
== NULL
&& ConnectDataLength
!= 0)
311 return(STATUS_NO_MEMORY
);
313 Status
= MmCopyFromCaller(ConnectData
,
316 if (!NT_SUCCESS(Status
))
318 ExFreePool(ConnectData
);
325 * Reference the named port.
327 Status
= ObReferenceObjectByName (PortName
,
330 PORT_ALL_ACCESS
, /* DesiredAccess */
335 if (!NT_SUCCESS(Status
))
337 if (KeGetPreviousMode() != KernelMode
)
339 ExFreePool(ConnectData
);
345 * Reference the send section object.
347 if (WriteMap
.SectionHandle
!= INVALID_HANDLE_VALUE
)
349 Status
= ObReferenceObjectByHandle(WriteMap
.SectionHandle
,
350 SECTION_MAP_READ
| SECTION_MAP_WRITE
,
353 (PVOID
*)&SectionObject
,
355 if (!NT_SUCCESS(Status
))
357 ObDereferenceObject(NamedPort
);
358 if (KeGetPreviousMode() != KernelMode
)
360 ExFreePool(ConnectData
);
367 SectionObject
= NULL
;
371 * Do the connection establishment.
373 Status
= EiConnectPort(&ConnectedPort
,
379 &WriteMap
.TargetViewBase
,
385 if (!NT_SUCCESS(Status
))
387 /* FIXME: Again, check what NT does here. */
388 if (UnsafeConnectDataLength
!= NULL
)
390 if (ExGetPreviousMode() != KernelMode
)
392 MmCopyToCaller(UnsafeConnectData
,
395 ExFreePool(ConnectData
);
397 MmCopyToCaller(UnsafeConnectDataLength
,
405 * Do some initial cleanup.
407 if (SectionObject
!= NULL
)
409 ObDereferenceObject(SectionObject
);
410 SectionObject
= NULL
;
412 ObDereferenceObject(NamedPort
);
416 * Copy the data back to the caller.
418 if (ExGetPreviousMode() != KernelMode
)
420 if (UnsafeConnectDataLength
!= NULL
)
422 Status
= MmCopyToCaller(UnsafeConnectDataLength
,
425 if (!NT_SUCCESS(Status
))
430 if (UnsafeConnectData
!= NULL
&& ConnectData
!= NULL
)
432 Status
= MmCopyToCaller(UnsafeConnectData
,
435 ExFreePool(ConnectData
);
436 if (!NT_SUCCESS(Status
))
442 Status
= ObInsertObject(ConnectedPort
,
447 &ConnectedPortHandle
);
448 if (!NT_SUCCESS(Status
))
452 Status
= MmCopyToCaller(UnsafeConnectedPortHandle
,
453 &ConnectedPortHandle
,
455 if (!NT_SUCCESS(Status
))
459 if (UnsafeWriteMap
!= NULL
)
461 Status
= MmCopyToCaller(UnsafeWriteMap
,
463 sizeof(LPC_SECTION_WRITE
));
464 if (!NT_SUCCESS(Status
))
469 if (UnsafeReadMap
!= NULL
)
471 Status
= MmCopyToCaller(UnsafeReadMap
,
473 sizeof(LPC_SECTION_READ
));
474 if (!NT_SUCCESS(Status
))
479 if (UnsafeMaximumMessageSize
!= NULL
)
481 Status
= MmCopyToCaller(UnsafeMaximumMessageSize
,
484 if (!NT_SUCCESS(Status
))
494 return(STATUS_SUCCESS
);
498 /**********************************************************************
500 * NtAcceptConnectPort/6
514 /*EXPORTED*/ NTSTATUS STDCALL
515 NtAcceptConnectPort (PHANDLE ServerPortHandle
,
516 HANDLE NamedPortHandle
,
517 PLPC_MESSAGE LpcMessage
,
519 PLPC_SECTION_WRITE WriteMap
,
520 PLPC_SECTION_READ ReadMap
)
524 PEPORT OurPort
= NULL
;
525 PQUEUEDMESSAGE ConnectionRequest
;
527 PEPORT_CONNECT_REQUEST_MESSAGE CRequest
;
528 PEPORT_CONNECT_REPLY_MESSAGE CReply
;
531 Size
= sizeof(EPORT_CONNECT_REPLY_MESSAGE
);
534 Size
+= LpcMessage
->DataSize
;
537 CReply
= ExAllocatePool(NonPagedPool
, Size
);
540 return(STATUS_NO_MEMORY
);
543 Status
= ObReferenceObjectByHandle(NamedPortHandle
,
549 if (!NT_SUCCESS(Status
))
556 * Create a port object for our side of the connection
560 Status
= ObCreateObject(ExGetPreviousMode(),
569 if (!NT_SUCCESS(Status
))
572 ObDereferenceObject(NamedPort
);
576 Status
= ObInsertObject ((PVOID
)OurPort
,
582 if (!NT_SUCCESS(Status
))
584 ObDereferenceObject(OurPort
);
586 ObDereferenceObject(NamedPort
);
590 LpcpInitializePort(OurPort
, EPORT_TYPE_SERVER_COMM_PORT
, NamedPort
);
594 * Dequeue the connection request
596 KeAcquireSpinLock(&NamedPort
->Lock
, &oldIrql
);
597 ConnectionRequest
= EiDequeueConnectMessagePort (NamedPort
);
598 KeReleaseSpinLock(&NamedPort
->Lock
, oldIrql
);
599 CRequest
= (PEPORT_CONNECT_REQUEST_MESSAGE
)(&ConnectionRequest
->Message
);
604 if (LpcMessage
!= NULL
)
606 memcpy(&CReply
->MessageHeader
, LpcMessage
, sizeof(LPC_MESSAGE
));
607 memcpy(&CReply
->ConnectData
, (PVOID
)(LpcMessage
+ 1),
608 LpcMessage
->DataSize
);
609 CReply
->MessageHeader
.MessageSize
=
610 sizeof(EPORT_CONNECT_REPLY_MESSAGE
) + LpcMessage
->DataSize
;
611 CReply
->MessageHeader
.DataSize
= CReply
->MessageHeader
.MessageSize
-
613 CReply
->ConnectDataLength
= LpcMessage
->DataSize
;
617 CReply
->MessageHeader
.MessageSize
= sizeof(EPORT_CONNECT_REPLY_MESSAGE
);
618 CReply
->MessageHeader
.DataSize
= sizeof(EPORT_CONNECT_REPLY_MESSAGE
) -
620 CReply
->ConnectDataLength
= 0;
624 EiReplyOrRequestPort(ConnectionRequest
->Sender
,
625 &CReply
->MessageHeader
,
626 LPC_CONNECTION_REFUSED
,
628 KeReleaseSemaphore(&ConnectionRequest
->Sender
->Semaphore
,
632 ObDereferenceObject(ConnectionRequest
->Sender
);
633 ExFreePool(ConnectionRequest
);
635 ObDereferenceObject(NamedPort
);
636 return (STATUS_SUCCESS
);
640 * Prepare the connection.
642 if (WriteMap
!= NULL
)
644 PSECTION_OBJECT SectionObject
;
645 LARGE_INTEGER SectionOffset
;
647 Status
= ObReferenceObjectByHandle(WriteMap
->SectionHandle
,
648 SECTION_MAP_READ
| SECTION_MAP_WRITE
,
651 (PVOID
*)&SectionObject
,
653 if (!NT_SUCCESS(Status
))
658 SectionOffset
.QuadPart
= WriteMap
->SectionOffset
;
659 WriteMap
->TargetViewBase
= 0;
660 CReply
->ReceiveClientViewSize
= WriteMap
->ViewSize
;
661 Status
= MmMapViewOfSection(SectionObject
,
662 CRequest
->ConnectingProcess
,
663 &WriteMap
->TargetViewBase
,
665 CReply
->ReceiveClientViewSize
,
667 &CReply
->ReceiveClientViewSize
,
669 0 /* MEM_TOP_DOWN? */,
671 if (!NT_SUCCESS(Status
))
676 WriteMap
->ViewBase
= 0;
677 Status
= MmMapViewOfSection(SectionObject
,
678 PsGetCurrentProcess(),
685 0 /* MEM_TOP_DOWN? */,
687 if (!NT_SUCCESS(Status
))
692 ObDereferenceObject(SectionObject
);
694 if (ReadMap
!= NULL
&& CRequest
->SendSectionObject
!= NULL
)
696 LARGE_INTEGER SectionOffset
;
698 SectionOffset
= CRequest
->SendSectionOffset
;
699 ReadMap
->ViewSize
= CRequest
->SendViewSize
;
700 ReadMap
->ViewBase
= 0;
701 Status
= MmMapViewOfSection(CRequest
->SendSectionObject
,
702 PsGetCurrentProcess(),
705 CRequest
->SendViewSize
,
707 &CRequest
->SendViewSize
,
709 0 /* MEM_TOP_DOWN? */,
711 if (!NT_SUCCESS(Status
))
722 CReply
->SendServerViewBase
= ReadMap
->ViewBase
;
726 CReply
->SendServerViewBase
= 0;
728 if (WriteMap
!= NULL
)
730 CReply
->ReceiveClientViewBase
= WriteMap
->TargetViewBase
;
732 CReply
->MaximumMessageSize
= PORT_MAX_MESSAGE_LENGTH
;
736 * Connect the two ports
738 OurPort
->OtherPort
= ConnectionRequest
->Sender
;
739 OurPort
->OtherPort
->OtherPort
= OurPort
;
740 EiReplyOrRequestPort(ConnectionRequest
->Sender
,
741 (PLPC_MESSAGE
)CReply
,
744 ExFreePool(ConnectionRequest
);
747 ObDereferenceObject(OurPort
);
748 ObDereferenceObject(NamedPort
);
750 return (STATUS_SUCCESS
);
753 /**********************************************************************
755 * NtSecureConnectPort/9
758 * Connect to a named port and wait for the other side to
759 * accept the connection. Possibly verify that the server
760 * matches the ServerSid (trusted server).
765 * PortName: fully qualified name in the Ob name space;
772 * UserConnectInfoLength
777 NtSecureConnectPort (OUT PHANDLE ConnectedPort
,
778 IN PUNICODE_STRING PortName
,
779 IN PSECURITY_QUALITY_OF_SERVICE Qos
,
780 IN OUT PLPC_SECTION_WRITE WriteMap OPTIONAL
,
781 IN PSID ServerSid OPTIONAL
,
782 IN OUT PLPC_SECTION_READ ReadMap OPTIONAL
,
783 OUT PULONG MaxMessageSize OPTIONAL
,
784 IN OUT PVOID ConnectInfo OPTIONAL
,
785 IN OUT PULONG UserConnectInfoLength OPTIONAL
)
787 /* TODO: implement a new object type: WaitablePort */
788 /* TODO: verify the process' SID that hosts the rendez-vous port equals ServerSid */
789 return NtConnectPort (ConnectedPort
,
796 UserConnectInfoLength
);