test: lpcreply.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# lpcreply.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1989  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     lpcreply.c
    00008
    00009 Abstract:
    00010
    00011     Local Inter-Process Communication (LPC) reply system services.
    00012
    00013 Author:
    00014
    00015     Steve Wood (stevewo) 15-May-1989
    00016
    00017 Revision History:
    00018
    00019 --*/
    00020
    00021 #include "lpcp.h"
    00022
    00023 NTSTATUS
    00024 LpcpCopyRequestData (
    00025     IN BOOLEAN WriteToMessageData,
    00026     IN HANDLE PortHandle,
    00027     IN PPORT_MESSAGE Message,
    00028     IN ULONG DataEntryIndex,
    00029     IN PVOID Buffer,
    00030     IN ULONG BufferSize,
    00031     OUT PULONG NumberOfBytesCopied OPTIONAL
    00032     );
    00033
    00034 #ifdef ALLOC_PRAGMA
    00035 #pragma alloc_text(PAGE,NtReplyPort)
    00036 #pragma alloc_text(PAGE,NtReplyWaitReplyPort)
    00037 #pragma alloc_text(PAGE,NtReadRequestData)
    00038 #pragma alloc_text(PAGE,NtWriteRequestData)
    00039 #pragma alloc_text(PAGE,LpcpCopyRequestData)
    00040 #endif
    00041
    00042
    00043 NTSTATUS
    00044 NtReplyPort (
    00045     IN HANDLE PortHandle,
    00046     IN PPORT_MESSAGE ReplyMessage
    00047     )
    00048
    00049 /*++
    00050
    00051 Routine Description:
    00052
    00053     A client and server process can send a reply to a previous request
    00054     message with the NtReplyPort service:
    00055
    00056     The Type field of the message is set to LPC_REPLY by the service.  If the
    00057     MapInfoOffset field of the reply message is non-zero, then the
    00058     PORT_MAP_INFORMATION structure it points to will be processed and the
    00059     relevant pages in the caller's address space will be unmapped.
    00060
    00061     The ClientId and MessageId fields of the ReplyMessage structure are used
    00062     to identify the thread waiting for this reply.  If the target thread is
    00063     in fact waiting for this reply message, then the reply message is copied
    00064     into the thread's message buffer and the thread's wait is satisfied.
    00065
    00066     If the thread is not waiting for a reply or is waiting for a reply to
    00067     some other MessageId, then the message is placed in the message queue of
    00068     the port that is connected to the communication port specified by the
    00069     PortHandle parameter and the Type field of the message is set to
    00070     LPC_LOST_REPLY.
    00071
    00072 Arguments:
    00073
    00074     PortHandle - Specifies the handle of the communication port that the
    00075         original message was received from.
    00076
    00077     ReplyMessage - Specifies a pointer to the reply message to be sent.
    00078         The ClientId and MessageId fields determine which thread will
    00079         get the reply.
    00080
    00081 Return Value:
    00082
    00083     Status code that indicates whether or not the operation was
    00084     successful.
    00085
    00086 --*/
    00087
    00088 {
    00089     KPROCESSOR_MODE PreviousMode;
    00090     PLPCP_PORT_OBJECT PortObject;
    00091     PORT_MESSAGE CapturedReplyMessage;
    00092     NTSTATUS Status;
    00093     PLPCP_MESSAGE Msg;
    00094     PETHREAD CurrentThread;
    00095     PETHREAD WakeupThread;
    00096
    00097     PAGED_CODE();
    00098
    00099     CurrentThread = PsGetCurrentThread();
    00100
    00101     //
    00102     //  Get previous processor mode and probe output arguments if necessary.
    00103     //
    00104
    00105     PreviousMode = KeGetPreviousMode();
    00106
    00107     if (PreviousMode != KernelMode) {
    00108
    00109         try {
    00110
    00111             ProbeForRead( ReplyMessage,
    00112                           sizeof( *ReplyMessage ),
    00113                           sizeof( ULONG ));
    00114
    00115             CapturedReplyMessage = *ReplyMessage;
    00116
    00117         } except( EXCEPTION_EXECUTE_HANDLER ) {
    00118
    00119             return GetExceptionCode();
    00120         }
    00121
    00122     } else {
    00123
    00124         CapturedReplyMessage = *ReplyMessage;
    00125     }
    00126
    00127     //
    00128     //  Make sure DataLength is valid with respect to header size and total
    00129     //  length
    00130     //
    00131
    00132     if ((((CLONG)CapturedReplyMessage.u1.s1.DataLength) + sizeof( PORT_MESSAGE )) >
    00133         ((CLONG)CapturedReplyMessage.u1.s1.TotalLength)) {
    00134
    00135         return STATUS_INVALID_PARAMETER;
    00136     }
    00137
    00138     //
    00139     //  Make sure the user didn't give us a bogus reply message id
    00140     //
    00141
    00142     if (CapturedReplyMessage.MessageId == 0) {
    00143
    00144         return STATUS_INVALID_PARAMETER;
    00145     }
    00146
    00147     //
    00148     //  Reference the port object by handle
    00149     //
    00150
    00151     Status = LpcpReferencePortObject( PortHandle,
    00152                                       0,
    00153                                       PreviousMode,
    00154                                       &PortObject );
    00155
    00156     if (!NT_SUCCESS( Status )) {
    00157
    00158         return Status;
    00159     }
    00160
    00161     LpcpSaveThread (PortObject);
    00162
    00163     //
    00164     //  Validate the message length
    00165     //
    00166
    00167     if (((ULONG)CapturedReplyMessage.u1.s1.TotalLength > PortObject->MaxMessageLength) ||
    00168         ((ULONG)CapturedReplyMessage.u1.s1.TotalLength <= (ULONG)CapturedReplyMessage.u1.s1.DataLength)) {
    00169
    00170         ObDereferenceObject( PortObject );
    00171
    00172         return STATUS_PORT_MESSAGE_TOO_LONG;
    00173     }
    00174
    00175     //
    00176     //  Translate the ClientId from the connection request into a thread
    00177     //  pointer.  This is a referenced pointer to keep the thread from
    00178     //  evaporating out from under us.
    00179     //
    00180
    00181     Status = PsLookupProcessThreadByCid( &CapturedReplyMessage.ClientId,
    00182                                          NULL,
    00183                                          &WakeupThread );
    00184
    00185     if (!NT_SUCCESS( Status )) {
    00186
    00187         ObDereferenceObject( PortObject );
    00188
    00189         return Status;
    00190     }
    00191
    00192     //
    00193     //  Acquire the mutex that guards the LpcReplyMessage field of the thread
    00194     //  and get the pointer to the message that the thread is waiting for a
    00195     //  reply to.
    00196     //
    00197
    00198     LpcpAcquireLpcpLock();
    00199
    00200     Msg = (PLPCP_MESSAGE)LpcpAllocateFromPortZone( CapturedReplyMessage.u1.s1.TotalLength );
    00201
    00202     if (Msg == NULL) {
    00203
    00204         LpcpReleaseLpcpLock();
    00205
    00206         ObDereferenceObject( WakeupThread );
    00207         ObDereferenceObject( PortObject );
    00208
    00209         return STATUS_NO_MEMORY;
    00210     }
    00211
    00212     //
    00213     //  See if the thread is waiting for a reply to the message specified on
    00214     //  this call.  If not then a bogus message has been specified, so
    00215     //  release the mutex, dereference the thread and return failure.
    00216     //
    00217     //  We also fail this request if the caller isn't replying to a request
    00218     //  message.  For example, if the caller is replying to a connection
    00219     //  request
    00220     //
    00221
    00222     if ((WakeupThread->LpcReplyMessageId != CapturedReplyMessage.MessageId)
    00223
    00224             ||
    00225
    00226         ((WakeupThread->LpcReplyMessage != NULL) &&
    00227          (((PLPCP_MESSAGE)(WakeupThread->LpcReplyMessage))->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) != LPC_REQUEST)) {
    00228
    00229         LpcpPrint(( "%s Attempted reply to Thread %lx (%s)\n",
    00230                     PsGetCurrentProcess()->ImageFileName,
    00231                     WakeupThread,
    00232                     THREAD_TO_PROCESS( WakeupThread )->ImageFileName ));
    00233
    00234         LpcpPrint(( "failed.  MessageId == %u  Client Id: %x.%x\n",
    00235                     CapturedReplyMessage.MessageId,
    00236                     CapturedReplyMessage.ClientId.UniqueProcess,
    00237                     CapturedReplyMessage.ClientId.UniqueThread ));
    00238
    00239         LpcpPrint(( "         Thread MessageId == %u  Client Id: %x.%x\n",
    00240                     WakeupThread->LpcReplyMessageId,
    00241                     WakeupThread->Cid.UniqueProcess,
    00242                     WakeupThread->Cid.UniqueThread ));
    00243
    00244 #if DBG
    00245         if (LpcpStopOnReplyMismatch) {
    00246
    00247             DbgBreakPoint();
    00248         }
    00249 #endif
    00250
    00251         LpcpFreeToPortZone( Msg, TRUE );
    00252
    00253         LpcpReleaseLpcpLock();
    00254
    00255         ObDereferenceObject( WakeupThread );
    00256         ObDereferenceObject( PortObject );
    00257
    00258         return STATUS_REPLY_MESSAGE_MISMATCH;
    00259     }
    00260
    00261     //
    00262     //  Copy the reply message to the request message buffer.  Do this before
    00263     //  we actually fiddle with the wakeup threads fields.  Otherwise we
    00264     //  could mess up its state
    00265     //
    00266
    00267     try {
    00268
    00269         LpcpMoveMessage( &Msg->Request,
    00270                          &CapturedReplyMessage,
    00271                          (ReplyMessage + 1),
    00272                          LPC_REPLY,
    00273                          NULL );
    00274
    00275     } except( EXCEPTION_EXECUTE_HANDLER ) {
    00276
    00277         LpcpFreeToPortZone( Msg, TRUE );
    00278
    00279         LpcpReleaseLpcpLock();
    00280
    00281         ObDereferenceObject( WakeupThread );
    00282         ObDereferenceObject( PortObject );
    00283
    00284         return (Status = GetExceptionCode());
    00285     }
    00286
    00287     //
    00288     //  At this point we know the thread is waiting for our reply
    00289     //
    00290
    00291     LpcpTrace(( "%s Sending Reply Msg %lx (%u, %x) [%08x %08x %08x %08x] to Thread %lx (%s)\n",
    00292                 PsGetCurrentProcess()->ImageFileName,
    00293                 Msg,
    00294                 CapturedReplyMessage.MessageId,
    00295                 CapturedReplyMessage.u2.s2.DataInfoOffset,
    00296                 *((PULONG)(Msg+1)+0),
    00297                 *((PULONG)(Msg+1)+1),
    00298                 *((PULONG)(Msg+1)+2),
    00299                 *((PULONG)(Msg+1)+3),
    00300                 WakeupThread,
    00301                 THREAD_TO_PROCESS( WakeupThread )->ImageFileName ));
    00302
    00303     //
    00304     //  Locate and free the messsage from the port.  This call use to
    00305     //  test for (CapturedReplyMessage.u2.s2.DataInfoOffset != 0) as a
    00306     //  prerequisite for doing the call.
    00307     //
    00308
    00309     LpcpFreeDataInfoMessage( PortObject,
    00310                              CapturedReplyMessage.MessageId,
    00311                              CapturedReplyMessage.CallbackId );
    00312
    00313     //
    00314     //  Add an extra reference so LpcExitThread does not evaporate the
    00315     //  pointer before we get to the wait below
    00316     //
    00317
    00318     ObReferenceObject( WakeupThread );
    00319
    00320     //
    00321     //  Release the mutex that guards the LpcReplyMessage field after marking
    00322     //  message as being replied to.
    00323     //
    00324
    00325     Msg->RepliedToThread = WakeupThread;
    00326
    00327     WakeupThread->LpcReplyMessageId = 0;
    00328     WakeupThread->LpcReplyMessage = (PVOID)Msg;
    00329
    00330     //
    00331     //  Remove the thread from the reply rundown list as we are sending the
    00332     //  reply.
    00333     //
    00334
    00335     if (!WakeupThread->LpcExitThreadCalled && !IsListEmpty( &WakeupThread->LpcReplyChain )) {
    00336
    00337         RemoveEntryList( &WakeupThread->LpcReplyChain );
    00338
    00339         InitializeListHead( &WakeupThread->LpcReplyChain );
    00340     }
    00341
    00342     if ((CurrentThread->LpcReceivedMsgIdValid) &&
    00343         (CurrentThread->LpcReceivedMessageId == CapturedReplyMessage.MessageId)) {
    00344
    00345         CurrentThread->LpcReceivedMessageId = 0;
    00346         CurrentThread->LpcReceivedMsgIdValid = FALSE;
    00347     }
    00348
    00349     LpcpReleaseLpcpLock();
    00350
    00351     //
    00352     //  Wake up the thread that is waiting for an answer to its request
    00353     //  inside of NtRequestWaitReplyPort or NtReplyWaitReplyPort.  That
    00354     //  will dereference itself when it wakes up.
    00355     //
    00356
    00357     KeReleaseSemaphore( &WakeupThread->LpcReplySemaphore,
    00358                         0,
    00359                         1L,
    00360                         FALSE );
    00361
    00362     ObDereferenceObject( WakeupThread );
    00363
    00364     //
    00365     //  Dereference port object and return the system service status.
    00366     //
    00367
    00368     ObDereferenceObject( PortObject );
    00369
    00370     return Status;
    00371 }
    00372
    00373
    00374 NTSTATUS
    00375 NtReplyWaitReplyPort (
    00376     IN HANDLE PortHandle,
    00377     IN OUT PPORT_MESSAGE ReplyMessage
    00378     )
    00379
    00380 /*++
    00381
    00382 Routine Description:
    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     //  Get previous processor mode and probe output arguments if necessary.
    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     //  Make sure DataLength is valid with respect to header size and total length
    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     //  Make sure the user didn't give us a bogus reply message id
    00460     //
    00461
    00462     if (CapturedReplyMessage.MessageId == 0) {
    00463
    00464         return STATUS_INVALID_PARAMETER;
    00465     }
    00466
    00467     //
    00468     //  Reference the communication port object by handle.  Return status if
    00469     //  unsuccessful.
    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     //  Validate the message length
    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     //  Translate the ClientId from the connection request into a
    00498     //  thread pointer.  This is a referenced pointer to keep the thread
    00499     //  from evaporating out from under us.
    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     //  Acquire the mutex that gaurds the LpcReplyMessage field of
    00515     //  the thread and get the pointer to the message that the thread
    00516     //  is waiting for a reply to.
    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     //  See if the thread is waiting for a reply to the message
    00535     //  specified on this call.  If not then a bogus message
    00536     //  has been specified, so release the mutex, dereference the thread
    00537     //  and return failure.
    00538     //
    00539     //  We also fail this request if the caller isn't replying to a request
    00540     //  message.  For example, if the caller is replying to a connection
    00541     //  request
    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     //  Copy the reply message to the request message buffer.  Do this before
    00585     //  we actually fiddle with the wakeup threads fields.  Otherwise we
    00586     //  could mess up its state
    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     //  At this point we know the thread is waiting for our reply
    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     //  Locate and free the messsage from the port.  This call use to
    00627     //  test for (CapturedReplyMessage.u2.s2.DataInfoOffset != 0) as a
    00628     //  prerequisite for doing the call.
    00629     //
    00630
    00631     LpcpFreeDataInfoMessage( PortObject,
    00632                              CapturedReplyMessage.MessageId,
    00633                              CapturedReplyMessage.CallbackId );
    00634
    00635     //
    00636     //  Add an extra reference so LpcExitThread does not evaporate
    00637     //  the pointer before we get to the wait below
    00638     //
    00639
    00640     ObReferenceObject( WakeupThread );
    00641
    00642     //
    00643     //  Release the mutex that guards the LpcReplyMessage field
    00644     //  after marking message as being replied to.
    00645     //
    00646
    00647     Msg->RepliedToThread = WakeupThread;
    00648
    00649     WakeupThread->LpcReplyMessageId = 0;
    00650     WakeupThread->LpcReplyMessage = (PVOID)Msg;
    00651
    00652     //
    00653     //  Remove the thread from the reply rundown list as we are sending the reply.
    00654     //
    00655
    00656     if (!WakeupThread->LpcExitThreadCalled && !IsListEmpty( &WakeupThread->LpcReplyChain )) {
    00657
    00658         RemoveEntryList( &WakeupThread->LpcReplyChain );
    00659
    00660         InitializeListHead( &WakeupThread->LpcReplyChain );
    00661     }
    00662
    00663     //
    00664     //  Set ourselves up to get the following reply
    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     //  Wake up the thread that is waiting for an answer to its request
    00681     //  inside of NtRequestWaitReplyPort or NtReplyWaitReplyPort.  That
    00682     //  will dereference itself when it wakes up.
    00683     //
    00684
    00685     KeReleaseSemaphore( &WakeupThread->LpcReplySemaphore,
    00686                         1,
    00687                         1,
    00688                         FALSE );
    00689
    00690     ObDereferenceObject( WakeupThread );
    00691
    00692     //
    00693     //  And wait for a reply
    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         //  if the semaphore is signaled, then clear it
    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     //  If the wait succeeded, copy the reply to the reply buffer.
    00722     //
    00723
    00724     if (Status == STATUS_SUCCESS) {
    00725
    00726         //
    00727         //  Acquire the mutex that guards the request message queue.  Remove
    00728         //  the request message from the list of messages being processed and
    00729         //  free the message back to the queue's zone.  If the zone's free
    00730         //  list was zero before freeing this message then pulse the free
    00731         //  event after free the message so that threads waiting to allocate
    00732         //  a request message buffer will wake up.  Finally, release the mutex
    00733         //  and return the system service status.
    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             //  Acquire the LPC mutex and decrement the reference count for the
    00781             //  message.  If the reference count goes to zero the message will be
    00782             //  deleted.
    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 }
    00804
    00805
    00806 NTSTATUS
    00807 NtReadRequestData (
    00808     IN HANDLE PortHandle,
    00809     IN PPORT_MESSAGE Message,
    00810     IN ULONG DataEntryIndex,
    00811     OUT PVOID Buffer,
    00812     IN ULONG BufferSize,
    00813     OUT PULONG NumberOfBytesRead OPTIONAL
    00814     )
    00815
    00816 /*++
    00817
    00818 Routine Description:
    00819
    00820     This routine is used to copy data from a port message into the user
    00821     supplied buffer.
    00822
    00823 Arguments:
    00824
    00825     PortHandle - Supplies the port from which the message is being read
    00826
    00827     Message - Supplies the message that we are trying to read
    00828
    00829     DataEntryIndex - Supplies the index of the port data entry in the
    00830         preceeding message that we are reading
    00831
    00832     Buffer - Supplies the location into which the data is to be read
    00833
    00834     BufferSize - Supplies the size, in bytes, of the preceeding buffer
    00835
    00836     NumberOfBytesRead - Optionally returns the number of bytes read into
    00837         the buffer
    00838
    00839 Return Value:
    00840
    00841     NTSTATUS - An appropriate status value
    00842
    00843 --*/
    00844
    00845 {
    00846     PAGED_CODE();
    00847
    00848     return LpcpCopyRequestData( FALSE,
    00849                                 PortHandle,
    00850                                 Message,
    00851                                 DataEntryIndex,
    00852                                 Buffer,
    00853                                 BufferSize,
    00854                                 NumberOfBytesRead );
    00855 }
    00856
    00857
    00858 NTSTATUS
    00859 NtWriteRequestData (
    00860     IN HANDLE PortHandle,
    00861     IN PPORT_MESSAGE Message,
    00862     IN ULONG DataEntryIndex,
    00863     IN PVOID Buffer,
    00864     IN ULONG BufferSize,
    00865     OUT PULONG NumberOfBytesWritten OPTIONAL
    00866     )
    00867
    00868 /*++
    00869
    00870 Routine Description:
    00871
    00872     This routine is used to copy data from the user supplied buffer into the
    00873     port message
    00874
    00875 Arguments:
    00876
    00877     PortHandle - Supplies the port into which the message is being written
    00878
    00879     Message - Supplies the message that we are trying to write
    00880
    00881     DataEntryIndex - Supplies the index of the port data entry in the
    00882         preceeding message that we are writing
    00883
    00884     Buffer - Supplies the location into which the data is to be written
    00885
    00886     BufferSize - Supplies the size, in bytes, of the preceeding buffer
    00887
    00888     NumberOfBytesRead - Optionally returns the number of bytes written from
    00889         the buffer
    00890
    00891 Return Value:
    00892
    00893     NTSTATUS - An appropriate status value
    00894
    00895 --*/
    00896
    00897 {
    00898     PAGED_CODE();
    00899
    00900     return LpcpCopyRequestData( TRUE,
    00901                                 PortHandle,
    00902                                 Message,
    00903                                 DataEntryIndex,
    00904                                 Buffer,
    00905                                 BufferSize,
    00906                                 NumberOfBytesWritten );
    00907 }
    00908
    00909
    00910 //
    00911 //  Local support routine
    00912 //
    00913
    00914 NTSTATUS
    00915 LpcpCopyRequestData (
    00916     IN BOOLEAN WriteToMessageData,
    00917     IN HANDLE PortHandle,
    00918     IN PPORT_MESSAGE Message,
    00919     IN ULONG DataEntryIndex,
    00920     IN PVOID Buffer,
    00921     IN ULONG BufferSize,
    00922     OUT PULONG NumberOfBytesCopied OPTIONAL
    00923     )
    00924
    00925 /*++
    00926
    00927 Routine Description:
    00928
    00929     This routine will copy data to or from the user supplied buffer and the
    00930     port message data information buffer
    00931
    00932 Arguments:
    00933
    00934     WriteToMessageData - TRUE if the data is to be copied from the user buffer
    00935         to the message and FALSE otherwise
    00936
    00937     PortHandle - Supplies the port into which the message is being manipulated
    00938
    00939     Message - Supplies the message that we are trying to manipulate
    00940
    00941     DataEntryIndex - Supplies the index of the port data entry in the
    00942         preceeding message that we are transfering
    00943
    00944     Buffer - Supplies the location into which the data is to be transfered
    00945
    00946     BufferSize - Supplies the size, in bytes, of the preceeding buffer
    00947
    00948     NumberOfBytesRead - Optionally returns the number of bytes transfered from
    00949         the buffer
    00950
    00951 Return Value:
    00952
    00953     NTSTATUS - An appropriate status value
    00954
    00955 --*/
    00956
    00957 {
    00958     KPROCESSOR_MODE PreviousMode;
    00959     PLPCP_PORT_OBJECT PortObject;
    00960     PLPCP_MESSAGE Msg;
    00961     PLIST_ENTRY Head, Next;
    00962     NTSTATUS Status;
    00963     PETHREAD ClientThread;
    00964     PPORT_DATA_INFORMATION DataInfo;
    00965     PPORT_DATA_ENTRY DataEntry;
    00966     PORT_MESSAGE CapturedMessage;
    00967     PORT_DATA_INFORMATION CapturedDataInfo;
    00968     PORT_DATA_ENTRY CapturedDataEntry;
    00969     ULONG BytesCopied;
    00970
    00971     PAGED_CODE();
    00972
    00973     //
    00974     //  Get previous processor mode and probe output arguments if necessary.
    00975     //
    00976
    00977     PreviousMode = KeGetPreviousMode();
    00978
    00979     if (PreviousMode != KernelMode) {
    00980
    00981         try {
    00982
    00983             //
    00984             //  We are either reading or writing the user buffer
    00985             //
    00986
    00987             if (WriteToMessageData) {
    00988
    00989                 ProbeForRead( Buffer,
    00990                               BufferSize,
    00991                               1 );
    00992
    00993             } else {
    00994
    00995                 ProbeForWrite( Buffer,
    00996                                BufferSize,
    00997                                1 );
    00998             }
    00999
    01000             ProbeForRead( Message,
    01001                           sizeof( *Message ),
    01002                           sizeof( ULONG ));
    01003
    01004             CapturedMessage = *Message;
    01005
    01006             if (ARGUMENT_PRESENT( NumberOfBytesCopied )) {
    01007
    01008                 ProbeForWriteUlong( NumberOfBytesCopied );
    01009             }
    01010
    01011         } except( EXCEPTION_EXECUTE_HANDLER ) {
    01012
    01013             return GetExceptionCode();
    01014         }
    01015
    01016     } else {
    01017
    01018         CapturedMessage = *Message;
    01019     }
    01020
    01021     //
    01022     //  The message better have at least one data entry
    01023     //
    01024
    01025     if (CapturedMessage.u2.s2.DataInfoOffset == 0) {
    01026
    01027         return STATUS_INVALID_PARAMETER;
    01028     }
    01029
    01030     //
    01031     //  Reference the port object by handle
    01032     //
    01033
    01034     Status = LpcpReferencePortObject( PortHandle,
    01035                                       0,
    01036                                       PreviousMode,
    01037                                       &PortObject );
    01038
    01039     if (!NT_SUCCESS( Status )) {
    01040
    01041         return Status;
    01042     }
    01043
    01044     LpcpSaveThread (PortObject);
    01045
    01046     //
    01047     //  Translate the ClientId from the connection request into a
    01048     //  thread pointer.  This is a referenced pointer to keep the thread
    01049     //  from evaporating out from under us.
    01050     //
    01051
    01052     Status = PsLookupProcessThreadByCid( &CapturedMessage.ClientId,
    01053                                          NULL,
    01054                                          &ClientThread );
    01055
    01056     if (!NT_SUCCESS( Status )) {
    01057
    01058         ObDereferenceObject( PortObject );
    01059
    01060         return Status;
    01061     }
    01062
    01063     //
    01064     //  Acquire the mutex that guards the LpcReplyMessage field of
    01065     //  the thread and get the pointer to the message that the thread
    01066     //  is waiting for a reply to.
    01067     //
    01068
    01069     LpcpAcquireLpcpLock();
    01070
    01071     //
    01072     //  See if the thread is waiting for a reply to the message
    01073     //  specified on this call.  If not then a bogus message
    01074     //  has been specified, so release the mutex, dereference the thread
    01075     //  and return failure.
    01076     //
    01077
    01078     if (ClientThread->LpcReplyMessageId != CapturedMessage.MessageId) {
    01079
    01080         Status = STATUS_REPLY_MESSAGE_MISMATCH;
    01081
    01082     } else {
    01083
    01084         Status = STATUS_INVALID_PARAMETER;
    01085
    01086         Msg = LpcpFindDataInfoMessage( PortObject,
    01087                                        CapturedMessage.MessageId,
    01088                                        CapturedMessage.CallbackId );
    01089
    01090         if (Msg != NULL) {
    01091
    01092             DataInfo = (PPORT_DATA_INFORMATION)((PUCHAR)&Msg->Request +
    01093                                                 Msg->Request.u2.s2.DataInfoOffset);
    01094
    01095             //
    01096             //  Make sure the caller isn't asking for an index beyond what's
    01097             //  in the message
    01098             //
    01099
    01100             if (DataInfo->CountDataEntries > DataEntryIndex) {
    01101
    01102                 DataEntry = &DataInfo->DataEntries[ DataEntryIndex ];
    01103                 CapturedDataEntry = *DataEntry;
    01104
    01105                 if (CapturedDataEntry.Size >= BufferSize) {
    01106
    01107                     Status = STATUS_SUCCESS;
    01108                 }
    01109             }
    01110         }
    01111     }
    01112
    01113     if (!NT_SUCCESS( Status )) {
    01114
    01115         LpcpReleaseLpcpLock();
    01116
    01117         ObDereferenceObject( ClientThread );
    01118         ObDereferenceObject( PortObject );
    01119
    01120         return Status;
    01121     }
    01122
    01123     //
    01124     //  Release the mutex that guards the LpcReplyMessage field
    01125     //
    01126
    01127     LpcpReleaseLpcpLock();
    01128
    01129     //
    01130     //  Copy the message data
    01131     //
    01132
    01133     if (WriteToMessageData) {
    01134
    01135         Status = MmCopyVirtualMemory( PsGetCurrentProcess(),
    01136                                       Buffer,
    01137                                       THREAD_TO_PROCESS( ClientThread ),
    01138                                       CapturedDataEntry.Base,
    01139                                       BufferSize,
    01140                                       PreviousMode,
    01141                                       &BytesCopied );
    01142
    01143     } else {
    01144
    01145         Status = MmCopyVirtualMemory( THREAD_TO_PROCESS( ClientThread ),
    01146                                       CapturedDataEntry.Base,
    01147                                       PsGetCurrentProcess(),
    01148                                       Buffer,
    01149                                       BufferSize,
    01150                                       PreviousMode,
    01151                                       &BytesCopied );
    01152     }
    01153
    01154     if (ARGUMENT_PRESENT( NumberOfBytesCopied )) {
    01155
    01156         try {
    01157
    01158             *NumberOfBytesCopied = BytesCopied;
    01159
    01160         } except( EXCEPTION_EXECUTE_HANDLER ) {
    01161
    01162             NOTHING;
    01163         }
    01164     }
    01165
    01166     //
    01167     //  Dereference client thread and return the system service status.
    01168     //
    01169
    01170     ObDereferenceObject( ClientThread );
    01171     ObDereferenceObject( PortObject );
    01172
    01173     return Status;
    01174 }