00382 :
00383
00384
A client and server process can send a reply to a previous message and
00385 block waiting
for a reply
using the NtReplyWaitReplyPort service:
00386
00387 This service works
the same as
NtReplyPort, except that after delivering
00388
the reply message,
it blocks waiting
for a reply to a previous message.
00389 When
the reply
is received,
it will be placed in
the location specified
00390 by
the ReplyMessage parameter.
00391
00392 Arguments:
00393
00394
PortHandle - Specifies
the handle of
the communication port that
the
00395 original message was received from.
00396
00397
ReplyMessage - Specifies a pointer to
the reply message to be sent.
00398 The ClientId and MessageId fields determine which thread will
00399 get
the reply. This buffer also receives any reply that comes
00400 back from
the wait.
00401
00402 Return Value:
00403
00404
Status code that indicates whether or not
the operation was
00405 successful.
00406
00407 --*/
00408
00409 {
00410
KPROCESSOR_MODE PreviousMode;
00411
NTSTATUS Status;
00412
PLPCP_PORT_OBJECT PortObject;
00413 PORT_MESSAGE CapturedReplyMessage;
00414
PLPCP_MESSAGE Msg;
00415
PETHREAD CurrentThread;
00416
PETHREAD WakeupThread;
00417
00418
PAGED_CODE();
00419
00420 CurrentThread =
PsGetCurrentThread();
00421
00422
00423
00424
00425
00426 PreviousMode = KeGetPreviousMode();
00427
00428
if (PreviousMode !=
KernelMode) {
00429
00430
try {
00431
00432
ProbeForWrite( ReplyMessage,
00433
sizeof( *ReplyMessage ),
00434
sizeof( ULONG ));
00435
00436 CapturedReplyMessage = *
ReplyMessage;
00437
00438 } except( EXCEPTION_EXECUTE_HANDLER ) {
00439
00440
return GetExceptionCode();
00441 }
00442
00443 }
else {
00444
00445 CapturedReplyMessage = *
ReplyMessage;
00446 }
00447
00448
00449
00450
00451
00452
if ((((CLONG)CapturedReplyMessage.u1.s1.DataLength) +
sizeof( PORT_MESSAGE )) >
00453 ((CLONG)CapturedReplyMessage.u1.s1.TotalLength)) {
00454
00455
return STATUS_INVALID_PARAMETER;
00456 }
00457
00458
00459
00460
00461
00462
if (CapturedReplyMessage.MessageId == 0) {
00463
00464
return STATUS_INVALID_PARAMETER;
00465 }
00466
00467
00468
00469
00470
00471
00472
Status =
LpcpReferencePortObject( PortHandle,
00473 0,
00474 PreviousMode,
00475 &PortObject );
00476
00477
if (!
NT_SUCCESS( Status )) {
00478
00479
return Status;
00480 }
00481
00482
LpcpSaveThread (PortObject);
00483
00484
00485
00486
00487
00488
if (((ULONG)CapturedReplyMessage.u1.s1.TotalLength > PortObject->
MaxMessageLength) ||
00489 ((ULONG)CapturedReplyMessage.u1.s1.TotalLength <= (ULONG)CapturedReplyMessage.u1.s1.DataLength)) {
00490
00491
ObDereferenceObject( PortObject );
00492
00493
return STATUS_PORT_MESSAGE_TOO_LONG;
00494 }
00495
00496
00497
00498
00499
00500
00501
00502
Status =
PsLookupProcessThreadByCid( &CapturedReplyMessage.ClientId,
00503 NULL,
00504 &WakeupThread );
00505
00506
if (!
NT_SUCCESS( Status )) {
00507
00508
ObDereferenceObject( PortObject );
00509
00510
return Status;
00511 }
00512
00513
00514
00515
00516
00517
00518
00519
LpcpAcquireLpcpLock();
00520
00521 Msg = (
PLPCP_MESSAGE)
LpcpAllocateFromPortZone( CapturedReplyMessage.u1.s1.TotalLength );
00522
00523
if (Msg ==
NULL) {
00524
00525
LpcpReleaseLpcpLock();
00526
00527
ObDereferenceObject( WakeupThread );
00528
ObDereferenceObject( PortObject );
00529
00530
return STATUS_NO_MEMORY;
00531 }
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
if ((WakeupThread->
LpcReplyMessageId != CapturedReplyMessage.MessageId)
00545
00546 ||
00547
00548 ((WakeupThread->
LpcReplyMessage !=
NULL) &&
00549 (((
PLPCP_MESSAGE)(WakeupThread->
LpcReplyMessage))->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) != LPC_REQUEST)) {
00550
00551
LpcpPrint((
"%s Attempted reply wait reply to Thread %lx (%s)\n",
00552
PsGetCurrentProcess()->ImageFileName,
00553 WakeupThread,
00554
THREAD_TO_PROCESS( WakeupThread )->ImageFileName ));
00555
00556
LpcpPrint((
"failed. MessageId == %u Client Id: %x.%x\n",
00557 CapturedReplyMessage.MessageId,
00558 CapturedReplyMessage.ClientId.UniqueProcess,
00559 CapturedReplyMessage.ClientId.UniqueThread ));
00560
00561
LpcpPrint((
" Thread MessageId == %u Client Id: %x.%x\n",
00562 WakeupThread->
LpcReplyMessageId,
00563 WakeupThread->
Cid.UniqueProcess,
00564 WakeupThread->
Cid.UniqueThread ));
00565
00566
#if DBG
00567
if (LpcpStopOnReplyMismatch) {
00568
00569 DbgBreakPoint();
00570 }
00571
#endif
00572
00573
LpcpFreeToPortZone( Msg, TRUE );
00574
00575
LpcpReleaseLpcpLock();
00576
00577
ObDereferenceObject( WakeupThread );
00578
ObDereferenceObject( PortObject );
00579
00580
return STATUS_REPLY_MESSAGE_MISMATCH;
00581 }
00582
00583
00584
00585
00586
00587
00588
00589
try {
00590
00591
LpcpMoveMessage( &Msg->
Request,
00592 &CapturedReplyMessage,
00593 (ReplyMessage + 1),
00594 LPC_REPLY,
00595 NULL );
00596
00597 } except( EXCEPTION_EXECUTE_HANDLER ) {
00598
00599
LpcpFreeToPortZone( Msg, TRUE );
00600
00601
LpcpReleaseLpcpLock();
00602
00603
ObDereferenceObject( WakeupThread );
00604
ObDereferenceObject( PortObject );
00605
00606
return (
Status = GetExceptionCode());
00607 }
00608
00609
00610
00611
00612
00613
LpcpTrace((
"%s Sending Reply Wait Reply Msg %lx (%u, %x) [%08x %08x %08x %08x] to Thread %lx (%s)\n",
00614
PsGetCurrentProcess()->ImageFileName,
00615 Msg,
00616 CapturedReplyMessage.MessageId,
00617 CapturedReplyMessage.u2.s2.DataInfoOffset,
00618 *((PULONG)(Msg+1)+0),
00619 *((PULONG)(Msg+1)+1),
00620 *((PULONG)(Msg+1)+2),
00621 *((PULONG)(Msg+1)+3),
00622 WakeupThread,
00623
THREAD_TO_PROCESS( WakeupThread )->ImageFileName ));
00624
00625
00626
00627
00628
00629
00630
00631
LpcpFreeDataInfoMessage( PortObject,
00632 CapturedReplyMessage.MessageId,
00633 CapturedReplyMessage.CallbackId );
00634
00635
00636
00637
00638
00639
00640
ObReferenceObject( WakeupThread );
00641
00642
00643
00644
00645
00646
00647 Msg->RepliedToThread = WakeupThread;
00648
00649 WakeupThread->
LpcReplyMessageId = 0;
00650 WakeupThread->
LpcReplyMessage = (PVOID)Msg;
00651
00652
00653
00654
00655
00656
if (!WakeupThread->
LpcExitThreadCalled && !IsListEmpty( &WakeupThread->
LpcReplyChain )) {
00657
00658 RemoveEntryList( &WakeupThread->
LpcReplyChain );
00659
00660 InitializeListHead( &WakeupThread->
LpcReplyChain );
00661 }
00662
00663
00664
00665
00666
00667 CurrentThread->
LpcReplyMessageId = CapturedReplyMessage.MessageId;
00668 CurrentThread->
LpcReplyMessage =
NULL;
00669
00670
if ((CurrentThread->
LpcReceivedMsgIdValid) &&
00671 (CurrentThread->
LpcReceivedMessageId == CapturedReplyMessage.MessageId)) {
00672
00673 CurrentThread->
LpcReceivedMessageId = 0;
00674 CurrentThread->
LpcReceivedMsgIdValid =
FALSE;
00675 }
00676
00677
LpcpReleaseLpcpLock();
00678
00679
00680
00681
00682
00683
00684
00685
KeReleaseSemaphore( &WakeupThread->
LpcReplySemaphore,
00686 1,
00687 1,
00688 FALSE );
00689
00690
ObDereferenceObject( WakeupThread );
00691
00692
00693
00694
00695
00696
Status =
KeWaitForSingleObject( &CurrentThread->
LpcReplySemaphore,
00697 Executive,
00698 PreviousMode,
00699 FALSE,
00700 NULL );
00701
00702
if (
Status == STATUS_USER_APC) {
00703
00704
00705
00706
00707
00708
if (
KeReadStateSemaphore( &CurrentThread->
LpcReplySemaphore )) {
00709
00710
KeWaitForSingleObject( &CurrentThread->
LpcReplySemaphore,
00711 WrExecutive,
00712 KernelMode,
00713 FALSE,
00714 NULL );
00715
00716
Status = STATUS_SUCCESS;
00717 }
00718 }
00719
00720
00721
00722
00723
00724
if (
Status == STATUS_SUCCESS) {
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
LpcpAcquireLpcpLock();
00737
00738 Msg = CurrentThread->
LpcReplyMessage;
00739 CurrentThread->
LpcReplyMessage =
NULL;
00740
00741
#if DBG
00742
if (Msg !=
NULL) {
00743
00744
LpcpTrace((
"%s Got Reply Msg %lx (%u) [%08x %08x %08x %08x] for Thread %lx (%s)\n",
00745
PsGetCurrentProcess()->ImageFileName,
00746 Msg,
00747 Msg->Request.MessageId,
00748 *((PULONG)(Msg+1)+0),
00749 *((PULONG)(Msg+1)+1),
00750 *((PULONG)(Msg+1)+2),
00751 *((PULONG)(Msg+1)+3),
00752 CurrentThread,
00753
THREAD_TO_PROCESS( CurrentThread )->ImageFileName ));
00754
00755
if (!IsListEmpty( &Msg->Entry )) {
00756
00757
LpcpTrace((
"Reply Msg %lx has non-empty list entry\n", Msg ));
00758 }
00759 }
00760
#endif
00761
00762
LpcpReleaseLpcpLock();
00763
00764
if (Msg !=
NULL) {
00765
00766
try {
00767
00768
LpcpMoveMessage( ReplyMessage,
00769 &Msg->Request,
00770 (&Msg->Request) + 1,
00771 0,
00772 NULL );
00773
00774 } except( EXCEPTION_EXECUTE_HANDLER ) {
00775
00776
Status = GetExceptionCode();
00777 }
00778
00779
00780
00781
00782
00783
00784
00785
LpcpAcquireLpcpLock();
00786
00787
if (Msg->RepliedToThread !=
NULL) {
00788
00789
ObDereferenceObject( Msg->RepliedToThread );
00790
00791 Msg->RepliedToThread =
NULL;
00792 }
00793
00794
LpcpFreeToPortZone( Msg, TRUE );
00795
00796
LpcpReleaseLpcpLock();
00797 }
00798 }
00799
00800
ObDereferenceObject( PortObject );
00801
00802
return Status;
00803 }