00403 :
00404
00405
A client and server process can send a request and wait
for a reply
using
00406
the NtRequestWaitReplyPort service.
00407
00408 If
the Type field of
the RequestMessage structure
is euqal to LPC_REQUEST,
00409 then
this is identified as a callback request. The ClientId and MessageId
00410 fields are used to identify
the thread that
is waiting
for a reply. This
00411 thread
is unblocked and
the current thread that called
this service then
00412 blocks waiting
for a reply.
00413
00414 The Type field of
the message
is set to LPC_REQUEST by
the service.
00415 Otherwise
the Type field of
the message must be zero and
it will be set to
00416 LPC_REQUEST by
the service. The message pointed to by
the RequestMessage
00417 parameter
is placed in
the message queue of
the port connected to
the
00418 communication port specified by
the PortHandle parameter. This service
00419 returns an error
if PortHandle is invalid. The calling thread then blocks
00420 waiting
for a reply.
00421
00422 The reply message
is stored in
the location pointed to by
the ReplyMessage
00423 parameter. The ClientId, MessageId and message
type fields will be filled
00424 in by
the service.
00425
00426 Arguments:
00427
00428
PortHandle - Specifies
the handle of
the communication port to send
the
00429 request message to.
00430
00431
RequestMessage - Specifies a pointer to a request message to send.
00432
00433
ReplyMessage - Specifies
the address of a variable that will receive
the
00434 reply message. This parameter may point to
the same buffer as
the
00435
RequestMessage parameter.
00436
00437 Return Value:
00438
00439
NTSTATUS -
A status code that indicates whether or not
the operation was
00440 successful.
00441
00442 --*/
00443
00444 {
00445
PLPCP_PORT_OBJECT PortObject;
00446
PLPCP_PORT_OBJECT QueuePort;
00447
PLPCP_PORT_OBJECT RundownPort;
00448 PORT_MESSAGE CapturedRequestMessage;
00449 ULONG MsgType;
00450
PKSEMAPHORE ReleaseSemaphore;
00451
KPROCESSOR_MODE PreviousMode;
00452
NTSTATUS Status;
00453
PLPCP_MESSAGE Msg;
00454
PETHREAD CurrentThread;
00455
PETHREAD WakeupThread;
00456 BOOLEAN CallbackRequest;
00457 PORT_DATA_INFORMATION CapturedDataInfo;
00458
00459
PAGED_CODE();
00460
00461
00462
00463
00464
00465 CurrentThread =
PsGetCurrentThread();
00466
00467
if (CurrentThread->
LpcExitThreadCalled) {
00468
00469
return STATUS_THREAD_IS_TERMINATING;
00470 }
00471
00472
00473
00474
00475
00476 PreviousMode = KeGetPreviousMode();
00477
00478
if (PreviousMode !=
KernelMode) {
00479
00480
try {
00481
00482
ProbeForRead( RequestMessage,
00483
sizeof( *RequestMessage ),
00484
sizeof( ULONG ));
00485
00486 CapturedRequestMessage = *
RequestMessage;
00487 CapturedRequestMessage.u2.s2.Type &= ~LPC_KERNELMODE_MESSAGE;
00488
00489
ProbeForWrite( ReplyMessage,
00490
sizeof( *ReplyMessage ),
00491
sizeof( ULONG ));
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
if (CapturedRequestMessage.u2.s2.DataInfoOffset != 0) {
00510
00511 PPORT_DATA_INFORMATION DataInfo;
00512 PPORT_DATA_ENTRY DataEntry;
00513
00514
if (((ULONG)CapturedRequestMessage.u2.s2.DataInfoOffset) > (CapturedRequestMessage.u1.s1.TotalLength -
sizeof(PORT_DATA_INFORMATION))) {
00515
00516
return STATUS_INVALID_PARAMETER;
00517 }
00518
00519
if ((ULONG)CapturedRequestMessage.u2.s2.DataInfoOffset <
sizeof(PORT_MESSAGE)) {
00520
00521
return STATUS_INVALID_PARAMETER;
00522 }
00523
00524 DataInfo = (PPORT_DATA_INFORMATION)(((PUCHAR)
RequestMessage) + CapturedRequestMessage.u2.s2.DataInfoOffset);
00525
00526
ProbeForRead( DataInfo,
00527
sizeof( *DataInfo ),
00528
sizeof( ULONG ));
00529
00530 CapturedDataInfo = *DataInfo;
00531
00532 DataEntry = &(DataInfo->DataEntries[CapturedDataInfo.CountDataEntries]);
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
if (((PUCHAR)DataEntry < (PUCHAR)DataInfo +
sizeof(CapturedDataInfo.CountDataEntries) + CapturedDataInfo.CountDataEntries) ||
00553 ((((PUCHAR)
RequestMessage) + CapturedRequestMessage.u1.s1.TotalLength) < (PUCHAR)DataEntry)) {
00554
00555
return STATUS_INVALID_PARAMETER;
00556 }
00557 }
00558
00559 } except( EXCEPTION_EXECUTE_HANDLER ) {
00560
00561
Status = GetExceptionCode();
00562
00563
return Status;
00564 }
00565
00566 }
else {
00567
00568 CapturedRequestMessage = *
RequestMessage;
00569
00570
if (CapturedRequestMessage.u2.s2.DataInfoOffset != 0) {
00571
00572 PPORT_DATA_INFORMATION DataInfo;
00573
00574 DataInfo = (PPORT_DATA_INFORMATION)(((PUCHAR)
RequestMessage) + CapturedRequestMessage.u2.s2.DataInfoOffset);
00575
00576 CapturedDataInfo = *DataInfo;
00577 }
00578 }
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
if ((CapturedRequestMessage.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) == LPC_REQUEST) {
00589
00590 CallbackRequest =
TRUE;
00591
00592 }
else if ((CapturedRequestMessage.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) != 0) {
00593
00594
return STATUS_INVALID_PARAMETER;
00595
00596 }
else {
00597
00598 CapturedRequestMessage.u2.s2.Type |= LPC_REQUEST;
00599 CallbackRequest =
FALSE;
00600 }
00601
00602
00603
00604
00605
00606
if ((((CLONG)CapturedRequestMessage.u1.s1.DataLength) +
sizeof( PORT_MESSAGE )) >
00607 ((CLONG)CapturedRequestMessage.u1.s1.TotalLength)) {
00608
00609
return STATUS_INVALID_PARAMETER;
00610 }
00611
00612
00613
00614
00615
00616
00617
Status =
LpcpReferencePortObject( PortHandle,
00618 0,
00619 PreviousMode,
00620 &PortObject );
00621
00622
if (!
NT_SUCCESS( Status )) {
00623
00624
return Status;
00625 }
00626
00627
00628
00629
00630
00631
if (((ULONG)CapturedRequestMessage.u1.s1.TotalLength > PortObject->
MaxMessageLength) ||
00632 ((ULONG)CapturedRequestMessage.u1.s1.TotalLength <= (ULONG)CapturedRequestMessage.u1.s1.DataLength)) {
00633
00634
ObDereferenceObject( PortObject );
00635
00636
return STATUS_PORT_MESSAGE_TOO_LONG;
00637 }
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
LpcpAcquireLpcpLock();
00650
00651 Msg = (
PLPCP_MESSAGE)
LpcpAllocateFromPortZone( CapturedRequestMessage.u1.s1.TotalLength );
00652
00653
LpcpReleaseLpcpLock();
00654
00655
if (Msg ==
NULL) {
00656
00657
ObDereferenceObject( PortObject );
00658
00659
return STATUS_NO_MEMORY;
00660 }
00661
00662 MsgType = CapturedRequestMessage.u2.s2.Type;
00663
00664
00665
00666
00667
00668
if (CallbackRequest) {
00669
00670
00671
00672
00673
00674
if (CapturedRequestMessage.MessageId == 0) {
00675
00676
LpcpFreeToPortZone( Msg, FALSE );
00677
00678
ObDereferenceObject( PortObject );
00679
00680
return STATUS_INVALID_PARAMETER;
00681 }
00682
00683
00684
00685
00686
00687
00688
00689
Status =
PsLookupProcessThreadByCid( &CapturedRequestMessage.ClientId,
00690 NULL,
00691 &WakeupThread );
00692
00693
if (!
NT_SUCCESS( Status )) {
00694
00695
LpcpFreeToPortZone( Msg, FALSE );
00696
00697
ObDereferenceObject( PortObject );
00698
00699
return Status;
00700 }
00701
00702
00703
00704
00705
00706
00707
00708
LpcpAcquireLpcpLock();
00709
00710
00711
00712
00713
00714
00715
00716
00717
if ((WakeupThread->
LpcReplyMessageId != CapturedRequestMessage.MessageId)
00718
00719 ||
00720
00721 ((WakeupThread->
LpcReplyMessage !=
NULL) &&
00722 (((
PLPCP_MESSAGE)(WakeupThread->
LpcReplyMessage))->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) != LPC_REQUEST)) {
00723
00724
LpcpPrint((
"%s Attempted CallBack Request to Thread %lx (%s)\n",
00725
PsGetCurrentProcess()->ImageFileName,
00726 WakeupThread,
00727
THREAD_TO_PROCESS( WakeupThread )->ImageFileName ));
00728
00729
LpcpPrint((
"failed. MessageId == %u Client Id: %x.%x\n",
00730 CapturedRequestMessage.MessageId,
00731 CapturedRequestMessage.ClientId.UniqueProcess,
00732 CapturedRequestMessage.ClientId.UniqueThread ));
00733
00734
LpcpPrint((
" Thread MessageId == %u Client Id: %x.%x\n",
00735 WakeupThread->
LpcReplyMessageId,
00736 WakeupThread->
Cid.UniqueProcess,
00737 WakeupThread->
Cid.UniqueThread ));
00738
00739
#if DBG
00740
if (LpcpStopOnReplyMismatch) {
00741
00742 DbgBreakPoint();
00743 }
00744
#endif
00745
00746
LpcpFreeToPortZone( Msg, TRUE );
00747
00748
LpcpReleaseLpcpLock();
00749
00750
ObDereferenceObject( WakeupThread );
00751
ObDereferenceObject( PortObject );
00752
00753
return STATUS_REPLY_MESSAGE_MISMATCH;
00754 }
00755
00756
00757
00758
00759
00760
try {
00761
00762
LpcpMoveMessage( &Msg->
Request,
00763 &CapturedRequestMessage,
00764 (RequestMessage + 1),
00765 MsgType,
00766 &CurrentThread->
Cid );
00767
00768
if (CapturedRequestMessage.u2.s2.DataInfoOffset != 0) {
00769
00770 PPORT_DATA_INFORMATION DataInfo;
00771
00772 DataInfo = (PPORT_DATA_INFORMATION)(((PUCHAR)
RequestMessage) + CapturedRequestMessage.u2.s2.DataInfoOffset);
00773
00774
if ( DataInfo->CountDataEntries != CapturedDataInfo.CountDataEntries ) {
00775
00776
Status = STATUS_INVALID_PARAMETER;
00777 }
00778 }
00779 } except( EXCEPTION_EXECUTE_HANDLER ) {
00780
00781
Status = GetExceptionCode();
00782 }
00783
00784
if (!
NT_SUCCESS( Status )) {
00785
00786
LpcpFreeToPortZone( Msg, FALSE );
00787
00788
LpcpReleaseLpcpLock();
00789
00790
ObDereferenceObject( WakeupThread );
00791
ObDereferenceObject( PortObject );
00792
00793
return Status;
00794 }
00795
00796
00797
00798
00799
00800
00801 QueuePort =
NULL;
00802 Msg->
PortContext =
NULL;
00803
00804
if ((PortObject->
Flags &
PORT_TYPE) ==
SERVER_CONNECTION_PORT) {
00805
00806 RundownPort = PortObject;
00807
00808 }
else {
00809
00810 RundownPort = PortObject->
ConnectedPort;
00811
00812
if (RundownPort ==
NULL) {
00813
00814
LpcpFreeToPortZone( Msg, TRUE );
00815
00816
LpcpReleaseLpcpLock();
00817
00818
ObDereferenceObject( WakeupThread );
00819
ObDereferenceObject( PortObject );
00820
00821
return STATUS_PORT_DISCONNECTED;
00822 }
00823
00824
if ((PortObject->
Flags &
PORT_TYPE) ==
CLIENT_COMMUNICATION_PORT) {
00825
00826 Msg->
PortContext = RundownPort->
PortContext;
00827 }
00828 }
00829
00830 Msg->
Request.CallbackId =
LpcpGenerateCallbackId();
00831
00832
LpcpTrace((
"%s CallBack Request (%s) Msg %lx (%u.%u) [%08x %08x %08x %08x] to Thread %lx (%s)\n",
00833
PsGetCurrentProcess()->ImageFileName,
00834 LpcpMessageTypeName[ Msg->
Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE ],
00835 Msg,
00836 Msg->
Request.MessageId,
00837 Msg->
Request.CallbackId,
00838 *((PULONG)(Msg+1)+0),
00839 *((PULONG)(Msg+1)+1),
00840 *((PULONG)(Msg+1)+2),
00841 *((PULONG)(Msg+1)+3),
00842 WakeupThread,
00843
THREAD_TO_PROCESS( WakeupThread )->ImageFileName ));
00844
00845
00846
00847
00848
00849
00850
ObReferenceObject( WakeupThread );
00851
00852 Msg->RepliedToThread = WakeupThread;
00853
00854 WakeupThread->
LpcReplyMessageId = 0;
00855 WakeupThread->
LpcReplyMessage = (PVOID)Msg;
00856
00857
00858
00859
00860
00861
if (!IsListEmpty( &WakeupThread->
LpcReplyChain )) {
00862
00863 RemoveEntryList( &WakeupThread->
LpcReplyChain );
00864
00865 InitializeListHead( &WakeupThread->
LpcReplyChain );
00866 }
00867
00868 CurrentThread->
LpcReplyMessageId = Msg->Request.MessageId;
00869 CurrentThread->
LpcReplyMessage =
NULL;
00870
00871 InsertTailList( &RundownPort->
LpcReplyChainHead, &CurrentThread->
LpcReplyChain );
00872
00873
LpcpReleaseLpcpLock();
00874
00875
00876
00877
00878
00879
00880 ReleaseSemaphore = &WakeupThread->
LpcReplySemaphore;
00881
00882 }
else {
00883
00884
00885
00886
00887
00888
00889
try {
00890
00891
LpcpMoveMessage( &Msg->
Request,
00892 &CapturedRequestMessage,
00893 (RequestMessage + 1),
00894 MsgType,
00895 &CurrentThread->
Cid );
00896
00897
if (CapturedRequestMessage.u2.s2.DataInfoOffset != 0) {
00898
00899 PPORT_DATA_INFORMATION DataInfo;
00900
00901 DataInfo = (PPORT_DATA_INFORMATION)(((PUCHAR)
RequestMessage) + CapturedRequestMessage.u2.s2.DataInfoOffset);
00902
00903
if ( DataInfo->CountDataEntries != CapturedDataInfo.CountDataEntries ) {
00904
00905
LpcpFreeToPortZone( Msg, FALSE );
00906
00907
ObDereferenceObject( PortObject );
00908
00909
return STATUS_INVALID_PARAMETER;
00910 }
00911 }
00912 } except( EXCEPTION_EXECUTE_HANDLER ) {
00913
00914
LpcpFreeToPortZone( Msg, FALSE );
00915
00916
ObDereferenceObject( PortObject );
00917
00918
return GetExceptionCode();
00919 }
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
LpcpAcquireLpcpLock();
00932
00933 Msg->
PortContext =
NULL;
00934
00935
if ((PortObject->
Flags &
PORT_TYPE) !=
SERVER_CONNECTION_PORT) {
00936
00937 QueuePort = PortObject->
ConnectedPort;
00938
00939
if (QueuePort ==
NULL) {
00940
00941
LpcpFreeToPortZone( Msg, TRUE );
00942
00943
LpcpReleaseLpcpLock();
00944
00945
ObDereferenceObject( PortObject );
00946
00947
return STATUS_PORT_DISCONNECTED;
00948 }
00949
00950 RundownPort = QueuePort;
00951
00952
if ((PortObject->
Flags &
PORT_TYPE) ==
CLIENT_COMMUNICATION_PORT) {
00953
00954 Msg->
PortContext = QueuePort->PortContext;
00955 QueuePort = PortObject->
ConnectionPort;
00956
00957 }
else if ((PortObject->
Flags &
PORT_TYPE) !=
SERVER_COMMUNICATION_PORT) {
00958
00959 QueuePort = PortObject->
ConnectionPort;
00960 }
00961
00962 }
else {
00963
00964 QueuePort = PortObject;
00965 RundownPort = PortObject;
00966 }
00967
00968
00969
00970
00971
00972
00973 Msg->
RepliedToThread =
NULL;
00974 Msg->
Request.MessageId =
LpcpGenerateMessageId();
00975 Msg->
Request.CallbackId = 0;
00976
00977 CurrentThread->
LpcReplyMessageId = Msg->
Request.MessageId;
00978 CurrentThread->
LpcReplyMessage =
NULL;
00979
00980 InsertTailList( &QueuePort->
MsgQueue.
ReceiveHead, &Msg->
Entry );
00981 InsertTailList( &RundownPort->
LpcReplyChainHead, &CurrentThread->
LpcReplyChain );
00982
00983
LpcpTrace((
"%s Send Request (%s) Msg %lx (%u) [%08x %08x %08x %08x] to Port %lx (%s)\n",
00984
PsGetCurrentProcess()->ImageFileName,
00985 LpcpMessageTypeName[ Msg->
Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE ],
00986 Msg,
00987 Msg->
Request.MessageId,
00988 *((PULONG)(Msg+1)+0),
00989 *((PULONG)(Msg+1)+1),
00990 *((PULONG)(Msg+1)+2),
00991 *((PULONG)(Msg+1)+3),
00992 QueuePort,
00993
LpcpGetCreatorName( QueuePort )));
00994
00995
LpcpReleaseLpcpLock();
00996
00997
00998
00999
01000
01001
01002 ReleaseSemaphore = QueuePort->
MsgQueue.
Semaphore;
01003
01004
01005
01006
01007
01008
01009
if ( QueuePort->
Flags &
PORT_WAITABLE ) {
01010
01011
KeSetEvent( &QueuePort->
WaitEvent,
01012 LPC_RELEASE_WAIT_INCREMENT,
01013 FALSE );
01014 }
01015 }
01016
01017
01018
01019
01020
01021
01022
01023
01024
Status =
KeReleaseSemaphore( ReleaseSemaphore,
01025 1,
01026 1,
01027 FALSE );
01028
01029
if (CallbackRequest) {
01030
01031
ObDereferenceObject( WakeupThread );
01032 }
01033
01034
01035
01036
01037
01038
Status =
KeWaitForSingleObject( &CurrentThread->
LpcReplySemaphore,
01039 WrLpcReply,
01040 PreviousMode,
01041 FALSE,
01042 NULL );
01043
01044
if (
Status == STATUS_USER_APC) {
01045
01046
01047
01048
01049
01050
if (
KeReadStateSemaphore( &CurrentThread->
LpcReplySemaphore )) {
01051
01052
KeWaitForSingleObject( &CurrentThread->
LpcReplySemaphore,
01053 WrExecutive,
01054 KernelMode,
01055 FALSE,
01056 NULL );
01057
01058
Status = STATUS_SUCCESS;
01059 }
01060 }
01061
01062
01063
01064
01065
01066
LpcpAcquireLpcpLock();
01067
01068 Msg = CurrentThread->
LpcReplyMessage;
01069
01070 CurrentThread->
LpcReplyMessage =
NULL;
01071 CurrentThread->
LpcReplyMessageId = 0;
01072
01073
01074
01075
01076
01077
01078
if (!IsListEmpty( &CurrentThread->
LpcReplyChain )) {
01079
01080 RemoveEntryList( &CurrentThread->
LpcReplyChain );
01081
01082 InitializeListHead( &CurrentThread->
LpcReplyChain );
01083 }
01084
01085
#if DBG
01086
if (
Status == STATUS_SUCCESS && Msg !=
NULL) {
01087
01088
LpcpTrace((
"%s Got Reply Msg %lx (%u) [%08x %08x %08x %08x] for Thread %lx (%s)\n",
01089
PsGetCurrentProcess()->ImageFileName,
01090 Msg,
01091 Msg->
Request.MessageId,
01092 *((PULONG)(Msg+1)+0),
01093 *((PULONG)(Msg+1)+1),
01094 *((PULONG)(Msg+1)+2),
01095 *((PULONG)(Msg+1)+3),
01096 CurrentThread,
01097
THREAD_TO_PROCESS( CurrentThread )->ImageFileName ));
01098
01099
if (!IsListEmpty( &Msg->Entry )) {
01100
01101
LpcpTrace((
"Reply Msg %lx has non-empty list entry\n", Msg ));
01102 }
01103 }
01104
#endif
01105
01106
LpcpReleaseLpcpLock();
01107
01108
01109
01110
01111
01112
if (
Status == STATUS_SUCCESS) {
01113
01114
if (Msg !=
NULL) {
01115
01116
try {
01117
01118
LpcpMoveMessage( ReplyMessage,
01119 &Msg->Request,
01120 (&Msg->Request) + 1,
01121 0,
01122 NULL );
01123
01124 } except( EXCEPTION_EXECUTE_HANDLER ) {
01125
01126
Status = GetExceptionCode();
01127 }
01128
01129
01130
01131
01132
01133
01134
01135
if (((Msg->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) == LPC_REQUEST) &&
01136 (Msg->Request.u2.s2.DataInfoOffset != 0)) {
01137
01138
LpcpSaveDataInfoMessage( PortObject, Msg );
01139
01140 }
else {
01141
01142
LpcpFreeToPortZone( Msg, FALSE );
01143 }
01144
01145 }
else {
01146
01147
Status = STATUS_LPC_REPLY_LOST;
01148 }
01149
01150 }
else {
01151
01152
01153
01154
01155
01156
LpcpAcquireLpcpLock();
01157
01158
LpcpTrace((
"%s NtRequestWaitReply wait failed - Status == %lx\n",
01159
PsGetCurrentProcess()->ImageFileName,
01160 Status ));
01161
01162
if (Msg !=
NULL) {
01163
01164
LpcpFreeToPortZone( Msg, TRUE );
01165 }
01166
01167
LpcpReleaseLpcpLock();
01168 }
01169
01170
ObDereferenceObject( PortObject );
01171
01172
01173
01174
01175
01176
return Status;
01177 }