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

lpcrecv.c File Reference

#include "lpcp.h"

Go to the source code of this file.

Functions

NTSTATUS NtReplyWaitReceivePort (IN HANDLE PortHandle, OUT PVOID *PortContext OPTIONAL, IN PPORT_MESSAGE ReplyMessage OPTIONAL, OUT PPORT_MESSAGE ReceiveMessage)
NTSTATUS NtReplyWaitReceivePortEx (IN HANDLE PortHandle, OUT PVOID *PortContext OPTIONAL, IN PPORT_MESSAGE ReplyMessage OPTIONAL, OUT PPORT_MESSAGE ReceiveMessage, IN PLARGE_INTEGER Timeout OPTIONAL)


Function Documentation

NTSTATUS NtReplyWaitReceivePort IN HANDLE  PortHandle,
OUT PVOID *PortContext  OPTIONAL,
IN PPORT_MESSAGE ReplyMessage  OPTIONAL,
OUT PPORT_MESSAGE  ReceiveMessage
 

Definition at line 29 of file lpcrecv.c.

References _ETHREAD::Cid, CLIENT_COMMUNICATION_PORT, _LPCP_PORT_OBJECT::ConnectionPort, _LPCP_MESSAGE::Entry, EXCEPTION_EXECUTE_HANDLER, FALSE, _LPCP_PORT_OBJECT::Flags, IS_SYSTEM_THREAD, KeReleaseSemaphore(), KeResetEvent(), KernelMode, KeWaitForSingleObject(), KPROCESSOR_MODE, _ETHREAD::LpcExitThreadCalled, LpcpAcquireLpcpLock, LpcpAllocateFromPortZone(), LpcpFreeDataInfoMessage(), LpcpFreeToPortZone(), LpcpGetCreatorName(), LpcpMoveMessage(), LpcpPrint, LpcpReferencePortObject, LpcpReleaseLpcpLock, LpcpSaveDataInfoMessage(), LpcpSaveThread, LpcpTrace, _ETHREAD::LpcReceivedMessageId, _ETHREAD::LpcReceivedMsgIdValid, _ETHREAD::LpcReplyChain, _ETHREAD::LpcReplyMessage, _ETHREAD::LpcReplyMessageId, _ETHREAD::LpcReplySemaphore, LpcWaitablePortObjectType, _LPCP_PORT_OBJECT::MaxMessageLength, _LPCP_PORT_OBJECT::MsgQueue, NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObject, ObReferenceObjectByHandle(), PAGED_CODE, PORT_TYPE, PORT_WAITABLE, _LPCP_MESSAGE::PortContext, PortHandle, ProbeForRead, ProbeForWrite(), ProbeForWriteUlong, PsGetCurrentProcess, PsGetCurrentThread, PsLookupProcessThreadByCid(), _LPCP_PORT_QUEUE::ReceiveHead, ReplyMessage(), _LPCP_MESSAGE::Request, _LPCP_PORT_QUEUE::Semaphore, Status, THREAD_TO_PROCESS, TRUE, UserMode, _LPCP_PORT_OBJECT::WaitEvent, and WrLpcReceive.

Referenced by DbgSspSrvApiLoop(), NtListenPort(), ServerThread(), UdbgTest1(), and UdbgTest2().

00038 : 00039 00040 This procedure is used by the server process to wait for a message from a 00041 client process 00042 00043 A client and server process can receive messages using the 00044 NtReplyWaitReceivePort service: 00045 00046 If the ReplyMessage parameter is specified, then the reply will be sent 00047 using NtReplyPort. 00048 00049 If the PortHandle parameter specifies a connection port, then the receive 00050 will return whenever a message is sent to a server communication port that 00051 does not have its own receive queue and the message is therefore queued to 00052 the receive queue of the connection port. 00053 00054 If the PortHandle parameter specifies a server communication port that 00055 does not have a receive queue, then behaves as if the associated 00056 connection port handle was specified. Otherwise the receive will return 00057 whenever message is placed in the receive queue associated with the 00058 server communication port. 00059 00060 The received message will be returned in the variable specified by the 00061 ReceiveMessage parameter. If the MapInfoOffset field of the reply message 00062 is non-zero, then the PORT_MAP_INFORMATION structure it points to will be 00063 processed and the relevant pages will be mapped into the caller's address 00064 space. The service returns an error if there is not enough room in the 00065 caller's address space to accomodate the mappings. 00066 00067 Arguments: 00068 00069 PortHandle - Specifies the handle of the connection or communication port 00070 to do the receive from. 00071 00072 PortContext - Specifies an optional pointer to a variable that is to 00073 receive the context value associated with the communication port that 00074 the message is being received from. This context variable was 00075 specified on the call to the NtAcceptConnectPort service. 00076 00077 ReplyMessage - This optional parameter specifies the address of a reply 00078 message to be sent. The ClientId and MessageId fields determine which 00079 thread will get the reply. See description of NtReplyPort for how the 00080 reply is sent. The reply is sent before blocking for the receive. 00081 00082 ReceiveMessage - Specifies the address of a variable to receive the 00083 message. 00084 00085 Return Value: 00086 00087 Status code that indicates whether or not the operation was successful. 00088 00089 --*/ 00090 00091 { 00092 PLPCP_PORT_OBJECT PortObject; 00093 PLPCP_PORT_OBJECT ReceivePort; 00094 PORT_MESSAGE CapturedReplyMessage; 00095 KPROCESSOR_MODE PreviousMode; 00096 KPROCESSOR_MODE WaitMode; 00097 NTSTATUS Status; 00098 PLPCP_MESSAGE Msg; 00099 PETHREAD CurrentThread; 00100 PETHREAD WakeupThread; 00101 00102 PAGED_CODE(); 00103 00104 CurrentThread = PsGetCurrentThread(); 00105 00106 // 00107 // Get previous processor mode 00108 // 00109 00110 PreviousMode = KeGetPreviousMode(); 00111 WaitMode = PreviousMode; 00112 00113 if (PreviousMode != KernelMode) { 00114 00115 try { 00116 00117 if (ARGUMENT_PRESENT( PortContext )) { 00118 00119 ProbeForWriteUlong( (PULONG)PortContext ); 00120 } 00121 00122 if (ARGUMENT_PRESENT( ReplyMessage)) { 00123 00124 ProbeForRead( ReplyMessage, 00125 sizeof( *ReplyMessage ), 00126 sizeof( ULONG )); 00127 00128 CapturedReplyMessage = *ReplyMessage; 00129 } 00130 00131 ProbeForWrite( ReceiveMessage, 00132 sizeof( *ReceiveMessage ), 00133 sizeof( ULONG )); 00134 00135 } except( EXCEPTION_EXECUTE_HANDLER ) { 00136 00137 return GetExceptionCode(); 00138 } 00139 00140 } else { 00141 00142 // 00143 // Kernel mode threads call with wait mode of user so that their 00144 // kernel stacks are swappable. Main consumer of this is 00145 // SepRmCommandThread 00146 // 00147 00148 if ( IS_SYSTEM_THREAD(CurrentThread) ) { 00149 00150 WaitMode = UserMode; 00151 } 00152 00153 if (ARGUMENT_PRESENT( ReplyMessage )) { 00154 00155 CapturedReplyMessage = *ReplyMessage; 00156 } 00157 } 00158 00159 if (ARGUMENT_PRESENT( ReplyMessage )) { 00160 00161 // 00162 // Make sure DataLength is valid with respect to header size and total 00163 // length 00164 // 00165 00166 if ((((CLONG)CapturedReplyMessage.u1.s1.DataLength) + sizeof( PORT_MESSAGE )) > 00167 ((CLONG)CapturedReplyMessage.u1.s1.TotalLength)) { 00168 00169 return STATUS_INVALID_PARAMETER; 00170 } 00171 00172 // 00173 // Make sure the user didn't give us a bogus reply message id 00174 // 00175 00176 if (CapturedReplyMessage.MessageId == 0) { 00177 00178 return STATUS_INVALID_PARAMETER; 00179 } 00180 } 00181 00182 // 00183 // Reference the port object by handle and if that doesn't work try 00184 // a waitable port object type 00185 // 00186 00187 Status = LpcpReferencePortObject( PortHandle, 00188 0, 00189 PreviousMode, 00190 &PortObject ); 00191 00192 if (!NT_SUCCESS( Status )) { 00193 00194 Status = ObReferenceObjectByHandle( PortHandle, 00195 0, 00196 LpcWaitablePortObjectType, 00197 PreviousMode, 00198 &PortObject, 00199 NULL ); 00200 00201 if ( !NT_SUCCESS( Status )) { 00202 00203 return Status; 00204 } 00205 } 00206 00207 LpcpSaveThread (PortObject); 00208 00209 // 00210 // Validate the message length 00211 // 00212 00213 if (ARGUMENT_PRESENT( ReplyMessage )) { 00214 00215 if (((ULONG)CapturedReplyMessage.u1.s1.TotalLength > PortObject->MaxMessageLength) || 00216 ((ULONG)CapturedReplyMessage.u1.s1.TotalLength <= (ULONG)CapturedReplyMessage.u1.s1.DataLength)) { 00217 00218 ObDereferenceObject( PortObject ); 00219 00220 return STATUS_PORT_MESSAGE_TOO_LONG; 00221 } 00222 } 00223 00224 // 00225 // The receive port we use is either the connection port for the port 00226 // object we were given if we were given a client communication port then 00227 // we expect to recieve the reply on the communication port itself. 00228 // 00229 00230 if ((PortObject->Flags & PORT_TYPE) != CLIENT_COMMUNICATION_PORT) { 00231 00232 ReceivePort = PortObject->ConnectionPort; 00233 00234 } else { 00235 00236 ReceivePort = PortObject; 00237 } 00238 00239 // 00240 // If ReplyMessage argument present, then send reply 00241 // 00242 00243 if (ARGUMENT_PRESENT( ReplyMessage )) { 00244 00245 // 00246 // Translate the ClientId from the connection request into a 00247 // thread pointer. This is a referenced pointer to keep the thread 00248 // from evaporating out from under us. 00249 // 00250 00251 Status = PsLookupProcessThreadByCid( &CapturedReplyMessage.ClientId, 00252 NULL, 00253 &WakeupThread ); 00254 00255 if (!NT_SUCCESS( Status )) { 00256 00257 ObDereferenceObject( PortObject ); 00258 return Status; 00259 } 00260 00261 // 00262 // Acquire the global Lpc mutex that gaurds the LpcReplyMessage 00263 // field of the thread and get the pointer to the message that 00264 // the thread is waiting for a reply to. 00265 // 00266 00267 LpcpAcquireLpcpLock(); 00268 00269 Msg = (PLPCP_MESSAGE)LpcpAllocateFromPortZone( CapturedReplyMessage.u1.s1.TotalLength ); 00270 00271 if (Msg == NULL) { 00272 00273 LpcpReleaseLpcpLock(); 00274 00275 ObDereferenceObject( WakeupThread ); 00276 ObDereferenceObject( PortObject ); 00277 00278 return STATUS_NO_MEMORY; 00279 } 00280 00281 // 00282 // See if the thread is waiting for a reply to the message 00283 // specified on this call. If not then a bogus message 00284 // has been specified, so release the mutex, dereference the thread 00285 // and return failure. 00286 // 00287 // We also fail this request if the caller isn't replying to a request 00288 // message. For example, if the caller is replying to a connection 00289 // request 00290 // 00291 00292 if ((WakeupThread->LpcReplyMessageId != CapturedReplyMessage.MessageId) 00293 00294 || 00295 00296 ((WakeupThread->LpcReplyMessage != NULL) && 00297 (((PLPCP_MESSAGE)(WakeupThread->LpcReplyMessage))->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) != LPC_REQUEST)) { 00298 00299 LpcpPrint(( "%s Attempted ReplyWaitReceive to Thread %lx (%s)\n", 00300 PsGetCurrentProcess()->ImageFileName, 00301 WakeupThread, 00302 THREAD_TO_PROCESS( WakeupThread )->ImageFileName )); 00303 00304 LpcpPrint(( "failed. MessageId == %u Client Id: %x.%x\n", 00305 CapturedReplyMessage.MessageId, 00306 CapturedReplyMessage.ClientId.UniqueProcess, 00307 CapturedReplyMessage.ClientId.UniqueThread )); 00308 00309 LpcpPrint(( " Thread MessageId == %u Client Id: %x.%x\n", 00310 WakeupThread->LpcReplyMessageId, 00311 WakeupThread->Cid.UniqueProcess, 00312 WakeupThread->Cid.UniqueThread )); 00313 00314 #if DBG 00315 if (LpcpStopOnReplyMismatch) { 00316 00317 DbgBreakPoint(); 00318 } 00319 #endif 00320 00321 LpcpFreeToPortZone( Msg, TRUE ); 00322 00323 LpcpReleaseLpcpLock(); 00324 00325 ObDereferenceObject( WakeupThread ); 00326 ObDereferenceObject( PortObject ); 00327 00328 return STATUS_REPLY_MESSAGE_MISMATCH; 00329 } 00330 00331 // 00332 // Copy the reply message to the request message buffer. Do this before 00333 // we actually fiddle with the wakeup threads fields. Otherwise we 00334 // could mess up its state 00335 // 00336 00337 try { 00338 00339 LpcpMoveMessage( &Msg->Request, 00340 &CapturedReplyMessage, 00341 (ReplyMessage + 1), 00342 LPC_REPLY, 00343 NULL ); 00344 00345 } except( EXCEPTION_EXECUTE_HANDLER ) { 00346 00347 LpcpFreeToPortZone( Msg, TRUE ); 00348 00349 LpcpReleaseLpcpLock(); 00350 00351 ObDereferenceObject( WakeupThread ); 00352 ObDereferenceObject( PortObject ); 00353 00354 return (Status = GetExceptionCode()); 00355 } 00356 00357 LpcpTrace(( "%s Sending Reply Msg %lx (%u.%u, %x) [%08x %08x %08x %08x] to Thread %lx (%s)\n", 00358 PsGetCurrentProcess()->ImageFileName, 00359 Msg, 00360 CapturedReplyMessage.MessageId, 00361 CapturedReplyMessage.CallbackId, 00362 CapturedReplyMessage.u2.s2.DataInfoOffset, 00363 *((PULONG)(Msg+1)+0), 00364 *((PULONG)(Msg+1)+1), 00365 *((PULONG)(Msg+1)+2), 00366 *((PULONG)(Msg+1)+3), 00367 WakeupThread, 00368 THREAD_TO_PROCESS( WakeupThread )->ImageFileName )); 00369 00370 // 00371 // Locate and free the messsage from the port. This call use to 00372 // test for (CapturedReplyMessage.u2.s2.DataInfoOffset != 0) as a 00373 // prerequisite for doing the call. 00374 // 00375 00376 LpcpFreeDataInfoMessage( PortObject, 00377 CapturedReplyMessage.MessageId, 00378 CapturedReplyMessage.CallbackId ); 00379 00380 // 00381 // Add an extra reference so LpcExitThread does not evaporate 00382 // the pointer before we get to the wait below 00383 // 00384 00385 ObReferenceObject( WakeupThread ); 00386 00387 // 00388 // Release the mutex that guards the LpcReplyMessage field 00389 // after marking message as being replied to. 00390 // 00391 00392 Msg->RepliedToThread = WakeupThread; 00393 00394 WakeupThread->LpcReplyMessageId = 0; 00395 WakeupThread->LpcReplyMessage = (PVOID)Msg; 00396 00397 // 00398 // Remove the thread from the reply rundown list as we are sending the reply. 00399 // 00400 00401 if (!WakeupThread->LpcExitThreadCalled && !IsListEmpty( &WakeupThread->LpcReplyChain )) { 00402 00403 RemoveEntryList( &WakeupThread->LpcReplyChain ); 00404 00405 InitializeListHead( &WakeupThread->LpcReplyChain ); 00406 } 00407 00408 if ((CurrentThread->LpcReceivedMsgIdValid) && 00409 (CurrentThread->LpcReceivedMessageId == CapturedReplyMessage.MessageId)) { 00410 00411 CurrentThread->LpcReceivedMessageId = 0; 00412 00413 CurrentThread->LpcReceivedMsgIdValid = FALSE; 00414 } 00415 00416 LpcpTrace(( "%s Waiting for message to Port %x (%s)\n", 00417 PsGetCurrentProcess()->ImageFileName, 00418 ReceivePort, 00419 LpcpGetCreatorName( ReceivePort ))); 00420 00421 LpcpReleaseLpcpLock(); 00422 00423 // 00424 // Wake up the thread that is waiting for an answer to its request 00425 // inside of NtRequestWaitReplyPort or NtReplyWaitReplyPort 00426 // 00427 00428 KeReleaseSemaphore( &WakeupThread->LpcReplySemaphore, 00429 1, 00430 1, 00431 FALSE ); 00432 00433 ObDereferenceObject( WakeupThread ); 00434 00435 Status = KeWaitForSingleObject( ReceivePort->MsgQueue.Semaphore, 00436 WrLpcReceive, 00437 WaitMode, 00438 FALSE, 00439 NULL ); 00440 00441 // 00442 // Fall into receive code. Client thread reference will be 00443 // returned by the client when it wakes up. 00444 // 00445 00446 } else { 00447 00448 // 00449 // The user did not give us a reply message to send off 00450 // 00451 // **** it looks like the only reason to have the then and else 00452 // clause both do a wait it to have the lpcp trace denote 00453 // the wait without a preceeding reply 00454 // 00455 // Wait for a message 00456 // 00457 00458 LpcpTrace(( "%s Waiting for message to Port %x (%s)\n", 00459 PsGetCurrentProcess()->ImageFileName, 00460 ReceivePort, 00461 LpcpGetCreatorName( ReceivePort ))); 00462 00463 Status = KeWaitForSingleObject( ReceivePort->MsgQueue.Semaphore, 00464 WrLpcReceive, 00465 WaitMode, 00466 FALSE, 00467 NULL ); 00468 } 00469 00470 // 00471 // At this point we've awoke from our wait for a receive 00472 // 00473 00474 if (Status == STATUS_SUCCESS) { 00475 00476 LpcpAcquireLpcpLock(); 00477 00478 // 00479 // See if we awoke without a message in our receive port 00480 // 00481 00482 if (IsListEmpty( &ReceivePort->MsgQueue.ReceiveHead )) { 00483 00484 if ( ReceivePort->Flags & PORT_WAITABLE ) { 00485 00486 KeResetEvent( &ReceivePort->WaitEvent ); 00487 } 00488 00489 LpcpReleaseLpcpLock(); 00490 00491 ObDereferenceObject( PortObject ); 00492 00493 return STATUS_UNSUCCESSFUL; 00494 } 00495 00496 // 00497 // We have a message in our recieve port. So let's pull it out 00498 // 00499 00500 Msg = (PLPCP_MESSAGE)RemoveHeadList( &ReceivePort->MsgQueue.ReceiveHead ); 00501 00502 if ( IsListEmpty( &ReceivePort->MsgQueue.ReceiveHead)) { 00503 00504 if ( ReceivePort->Flags & PORT_WAITABLE ) { 00505 00506 KeResetEvent( &ReceivePort->WaitEvent ); 00507 } 00508 } 00509 00510 InitializeListHead( &Msg->Entry ); 00511 00512 LpcpTrace(( "%s Receive Msg %lx (%u) from Port %lx (%s)\n", 00513 PsGetCurrentProcess()->ImageFileName, 00514 Msg, 00515 Msg->Request.MessageId, 00516 ReceivePort, 00517 LpcpGetCreatorName( ReceivePort ))); 00518 00519 // 00520 // Now make the thread state to be the message we're currently 00521 // working on 00522 // 00523 00524 CurrentThread->LpcReceivedMessageId = Msg->Request.MessageId; 00525 CurrentThread->LpcReceivedMsgIdValid = TRUE; 00526 00527 LpcpReleaseLpcpLock(); 00528 00529 try { 00530 00531 // 00532 // Check if the message is a connection request 00533 // 00534 00535 if ((Msg->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) == LPC_CONNECTION_REQUEST) { 00536 00537 PLPCP_CONNECTION_MESSAGE ConnectMsg; 00538 ULONG ConnectionInfoLength; 00539 PLPCP_MESSAGE TempMsg; 00540 00541 ConnectMsg = (PLPCP_CONNECTION_MESSAGE)(Msg + 1); 00542 00543 ConnectionInfoLength = Msg->Request.u1.s1.DataLength - sizeof( *ConnectMsg ); 00544 00545 // 00546 // Dont free message until NtAcceptConnectPort called, and if it's never called 00547 // then we'll keep the message until the client exits. 00548 // 00549 00550 TempMsg = Msg; 00551 Msg = NULL; 00552 00553 *ReceiveMessage = TempMsg->Request; 00554 00555 ReceiveMessage->u1.s1.TotalLength = (CSHORT)(sizeof( *ReceiveMessage ) + ConnectionInfoLength); 00556 ReceiveMessage->u1.s1.DataLength = (CSHORT)ConnectionInfoLength; 00557 00558 RtlMoveMemory( ReceiveMessage+1, 00559 ConnectMsg + 1, 00560 ConnectionInfoLength ); 00561 00562 if (ARGUMENT_PRESENT( PortContext )) { 00563 00564 *PortContext = NULL; 00565 } 00566 00567 // 00568 // Check if the message is not a reply 00569 // 00570 00571 } else if ((Msg->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) != LPC_REPLY) { 00572 00573 LpcpMoveMessage( ReceiveMessage, 00574 &Msg->Request, 00575 (&Msg->Request) + 1, 00576 0, 00577 NULL ); 00578 00579 if (ARGUMENT_PRESENT( PortContext )) { 00580 00581 *PortContext = Msg->PortContext; 00582 } 00583 00584 // 00585 // If message contains DataInfo for access via NtRead/WriteRequestData 00586 // then put the message on a list in the communication port and dont 00587 // free it. It will be freed when the server replies to the message. 00588 // 00589 00590 if (Msg->Request.u2.s2.DataInfoOffset != 0) { 00591 00592 LpcpSaveDataInfoMessage( PortObject, Msg ); 00593 Msg = NULL; 00594 } 00595 00596 // 00597 // Otherwise this is a reply message we just recieved 00598 // 00599 00600 } else { 00601 00602 LpcpPrint(( "LPC: Bogus reply message (%08x) in receive queue of connection port %08x\n", 00603 Msg, ReceivePort )); 00604 00605 KdBreakPoint(); 00606 } 00607 00608 } except( EXCEPTION_EXECUTE_HANDLER ) { 00609 00610 Status = GetExceptionCode(); // FIX, FIX 00611 } 00612 00613 // 00614 // Acquire the LPC mutex and decrement the reference count for the 00615 // message. If the reference count goes to zero the message will be 00616 // deleted. 00617 // 00618 00619 if (Msg != NULL) { 00620 00621 LpcpFreeToPortZone( Msg, FALSE ); 00622 } 00623 } 00624 00625 ObDereferenceObject( PortObject ); 00626 00627 // 00628 // And return to our caller 00629 // 00630 00631 return Status; 00632 }

NTSTATUS NtReplyWaitReceivePortEx IN HANDLE  PortHandle,
OUT PVOID *PortContext  OPTIONAL,
IN PPORT_MESSAGE ReplyMessage  OPTIONAL,
OUT PPORT_MESSAGE  ReceiveMessage,
IN PLARGE_INTEGER Timeout  OPTIONAL
 

Definition at line 635 of file lpcrecv.c.

References _ETHREAD::Cid, CLIENT_COMMUNICATION_PORT, _LPCP_PORT_OBJECT::ConnectionPort, _LPCP_MESSAGE::Entry, EXCEPTION_EXECUTE_HANDLER, FALSE, _LPCP_PORT_OBJECT::Flags, IS_SYSTEM_THREAD, KeReleaseSemaphore(), KeResetEvent(), KernelMode, KeWaitForSingleObject(), KPROCESSOR_MODE, _ETHREAD::LpcExitThreadCalled, LpcpAcquireLpcpLock, LpcpAllocateFromPortZone(), LpcpFreeDataInfoMessage(), LpcpFreeToPortZone(), LpcpGetCreatorName(), LpcpMoveMessage(), LpcpPrint, LpcpReferencePortObject, LpcpReleaseLpcpLock, LpcpSaveDataInfoMessage(), LpcpSaveThread, LpcpTrace, _ETHREAD::LpcReceivedMessageId, _ETHREAD::LpcReceivedMsgIdValid, _ETHREAD::LpcReplyChain, _ETHREAD::LpcReplyMessage, _ETHREAD::LpcReplyMessageId, _ETHREAD::LpcReplySemaphore, LpcWaitablePortObjectType, _LPCP_PORT_OBJECT::MsgQueue, NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObject, ObReferenceObjectByHandle(), PAGED_CODE, PORT_TYPE, PORT_WAITABLE, _LPCP_MESSAGE::PortContext, PortHandle, ProbeAndReadLargeInteger, ProbeForRead, ProbeForWrite(), ProbeForWriteUlong, PsGetCurrentProcess, PsGetCurrentThread, PsLookupProcessThreadByCid(), _LPCP_PORT_QUEUE::ReceiveHead, ReplyMessage(), _LPCP_MESSAGE::Request, _LPCP_PORT_QUEUE::Semaphore, Status, THREAD_TO_PROCESS, TRUE, UserMode, _LPCP_PORT_OBJECT::WaitEvent, and WrLpcReceive.

Referenced by RtlpLpcServerCallback().

00645 : 00646 00647 See NtReplyWaitReceivePort. 00648 00649 Arguments: 00650 00651 See NtReplyWaitReceivePort. 00652 00653 Timeout - Supplies an optional timeout value to use when waiting for a 00654 receive. 00655 00656 Return Value: 00657 00658 See NtReplyWaitReceivePort. 00659 00660 --*/ 00661 00662 { 00663 PLPCP_PORT_OBJECT PortObject; 00664 PLPCP_PORT_OBJECT ReceivePort; 00665 PORT_MESSAGE CapturedReplyMessage; 00666 KPROCESSOR_MODE PreviousMode; 00667 KPROCESSOR_MODE WaitMode; 00668 NTSTATUS Status; 00669 PLPCP_MESSAGE Msg; 00670 PETHREAD CurrentThread; 00671 PETHREAD WakeupThread; 00672 LARGE_INTEGER TimeoutValue ; 00673 00674 PAGED_CODE(); 00675 00676 CurrentThread = PsGetCurrentThread(); 00677 00678 TimeoutValue.QuadPart = 0 ; 00679 00680 // 00681 // Get previous processor mode 00682 // 00683 00684 PreviousMode = KeGetPreviousMode(); 00685 WaitMode = PreviousMode; 00686 00687 if (PreviousMode != KernelMode) { 00688 00689 try { 00690 00691 if (ARGUMENT_PRESENT( PortContext )) { 00692 00693 ProbeForWriteUlong( (PULONG)PortContext ); 00694 } 00695 00696 if (ARGUMENT_PRESENT( ReplyMessage)) { 00697 00698 ProbeForRead( ReplyMessage, 00699 sizeof( *ReplyMessage ), 00700 sizeof( ULONG )); 00701 00702 CapturedReplyMessage = *ReplyMessage; 00703 } 00704 00705 if (ARGUMENT_PRESENT( Timeout )) { 00706 00707 TimeoutValue = ProbeAndReadLargeInteger( Timeout ); 00708 00709 Timeout = &TimeoutValue ; 00710 } 00711 00712 ProbeForWrite( ReceiveMessage, 00713 sizeof( *ReceiveMessage ), 00714 sizeof( ULONG )); 00715 00716 } except( EXCEPTION_EXECUTE_HANDLER ) { 00717 00718 return GetExceptionCode(); 00719 } 00720 00721 } else { 00722 00723 // 00724 // Kernel mode threads call with wait mode of user so that their 00725 // kernel // stacks are swappable. Main consumer of this is 00726 // SepRmCommandThread 00727 // 00728 00729 if ( IS_SYSTEM_THREAD(CurrentThread) ) { 00730 00731 WaitMode = UserMode; 00732 } 00733 00734 if (ARGUMENT_PRESENT( ReplyMessage)) { 00735 00736 CapturedReplyMessage = *ReplyMessage; 00737 } 00738 } 00739 00740 if (ARGUMENT_PRESENT( ReplyMessage)) { 00741 00742 // 00743 // Make sure DataLength is valid with respect to header size and total 00744 // length 00745 // 00746 00747 if ((((CLONG)CapturedReplyMessage.u1.s1.DataLength) + sizeof( PORT_MESSAGE )) > 00748 ((CLONG)CapturedReplyMessage.u1.s1.TotalLength)) { 00749 00750 return STATUS_INVALID_PARAMETER; 00751 } 00752 00753 // 00754 // Make sure the user didn't give us a bogus reply message id 00755 // 00756 00757 if (CapturedReplyMessage.MessageId == 0) { 00758 00759 return STATUS_INVALID_PARAMETER; 00760 } 00761 } 00762 00763 // 00764 // Reference the port object by handle and if that doesn't work try 00765 // a waitable port object type 00766 // 00767 00768 Status = LpcpReferencePortObject( PortHandle, 00769 0, 00770 PreviousMode, 00771 &PortObject ); 00772 00773 if (!NT_SUCCESS( Status )) { 00774 00775 Status = ObReferenceObjectByHandle( PortHandle, 00776 0, 00777 LpcWaitablePortObjectType, 00778 PreviousMode, 00779 &PortObject, 00780 NULL ); 00781 00782 if ( !NT_SUCCESS( Status ) ) { 00783 00784 return Status; 00785 } 00786 } 00787 00788 LpcpSaveThread (PortObject); 00789 00790 // 00791 // The receive port we use is either the connection port for the port 00792 // object we were given if we were given a client communication port then 00793 // we expect to recieve the reply on the communication port itself. 00794 // 00795 00796 if ((PortObject->Flags & PORT_TYPE) != CLIENT_COMMUNICATION_PORT) { 00797 00798 ReceivePort = PortObject->ConnectionPort; 00799 00800 } else { 00801 00802 ReceivePort = PortObject; 00803 } 00804 00805 // 00806 // If ReplyMessage argument present, then send reply 00807 // 00808 00809 if (ARGUMENT_PRESENT( ReplyMessage )) { 00810 00811 // 00812 // Translate the ClientId from the connection request into a 00813 // thread pointer. This is a referenced pointer to keep the thread 00814 // from evaporating out from under us. 00815 // 00816 00817 Status = PsLookupProcessThreadByCid( &CapturedReplyMessage.ClientId, 00818 NULL, 00819 &WakeupThread ); 00820 00821 if (!NT_SUCCESS( Status )) { 00822 00823 ObDereferenceObject( PortObject ); 00824 return Status; 00825 } 00826 00827 // 00828 // Acquire the global Lpc mutex that gaurds the LpcReplyMessage 00829 // field of the thread and get the pointer to the message that 00830 // the thread is waiting for a reply to. 00831 // 00832 00833 LpcpAcquireLpcpLock(); 00834 00835 Msg = (PLPCP_MESSAGE)LpcpAllocateFromPortZone( CapturedReplyMessage.u1.s1.TotalLength ); 00836 00837 if (Msg == NULL) { 00838 00839 LpcpReleaseLpcpLock(); 00840 00841 ObDereferenceObject( WakeupThread ); 00842 ObDereferenceObject( PortObject ); 00843 00844 return STATUS_NO_MEMORY; 00845 } 00846 00847 // 00848 // See if the thread is waiting for a reply to the message 00849 // specified on this call. If not then a bogus message 00850 // has been specified, so release the mutex, dereference the thread 00851 // and return failure. 00852 // 00853 // We also fail this request if the caller isn't replying to a request 00854 // message. For example, if the caller is replying to a connection 00855 // request 00856 // 00857 00858 if ((WakeupThread->LpcReplyMessageId != CapturedReplyMessage.MessageId) 00859 00860 || 00861 00862 ((WakeupThread->LpcReplyMessage != NULL) && 00863 (((PLPCP_MESSAGE)(WakeupThread->LpcReplyMessage))->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) != LPC_REQUEST)) { 00864 00865 LpcpPrint(( "%s Attempted ReplyWaitReceive to Thread %lx (%s)\n", 00866 PsGetCurrentProcess()->ImageFileName, 00867 WakeupThread, 00868 THREAD_TO_PROCESS( WakeupThread )->ImageFileName )); 00869 00870 LpcpPrint(( "failed. MessageId == %u Client Id: %x.%x\n", 00871 CapturedReplyMessage.MessageId, 00872 CapturedReplyMessage.ClientId.UniqueProcess, 00873 CapturedReplyMessage.ClientId.UniqueThread )); 00874 00875 LpcpPrint(( " Thread MessageId == %u Client Id: %x.%x\n", 00876 WakeupThread->LpcReplyMessageId, 00877 WakeupThread->Cid.UniqueProcess, 00878 WakeupThread->Cid.UniqueThread )); 00879 00880 #if DBG 00881 if (LpcpStopOnReplyMismatch) { 00882 00883 DbgBreakPoint(); 00884 } 00885 #endif 00886 00887 LpcpFreeToPortZone( Msg, TRUE ); 00888 00889 LpcpReleaseLpcpLock(); 00890 00891 ObDereferenceObject( WakeupThread ); 00892 ObDereferenceObject( PortObject ); 00893 00894 return STATUS_REPLY_MESSAGE_MISMATCH; 00895 } 00896 00897 // 00898 // Copy the reply message to the request message buffer. Do this before 00899 // we actually fiddle with the wakeup threads fields. Otherwise we 00900 // could mess up its state 00901 // 00902 00903 try { 00904 00905 LpcpMoveMessage( &Msg->Request, 00906 &CapturedReplyMessage, 00907 (ReplyMessage + 1), 00908 LPC_REPLY, 00909 NULL ); 00910 00911 } except( EXCEPTION_EXECUTE_HANDLER ) { 00912 00913 LpcpFreeToPortZone( Msg, TRUE ); 00914 00915 LpcpReleaseLpcpLock(); 00916 00917 ObDereferenceObject( WakeupThread ); 00918 ObDereferenceObject( PortObject ); 00919 00920 return (Status = GetExceptionCode()); 00921 } 00922 00923 LpcpTrace(( "%s Sending Reply Msg %lx (%u.%u, %x) [%08x %08x %08x %08x] to Thread %lx (%s)\n", 00924 PsGetCurrentProcess()->ImageFileName, 00925 Msg, 00926 CapturedReplyMessage.MessageId, 00927 CapturedReplyMessage.CallbackId, 00928 CapturedReplyMessage.u2.s2.DataInfoOffset, 00929 *((PULONG)(Msg+1)+0), 00930 *((PULONG)(Msg+1)+1), 00931 *((PULONG)(Msg+1)+2), 00932 *((PULONG)(Msg+1)+3), 00933 WakeupThread, 00934 THREAD_TO_PROCESS( WakeupThread )->ImageFileName )); 00935 00936 // 00937 // Locate and free the messsage from the port. This call use to 00938 // test for (CapturedReplyMessage.u2.s2.DataInfoOffset != 0) as a 00939 // prerequisite for doing the call. 00940 // 00941 00942 LpcpFreeDataInfoMessage( PortObject, 00943 CapturedReplyMessage.MessageId, 00944 CapturedReplyMessage.CallbackId ); 00945 00946 // 00947 // Add an extra reference so LpcExitThread does not evaporate 00948 // the pointer before we get to the wait below 00949 // 00950 00951 ObReferenceObject( WakeupThread ); 00952 00953 // 00954 // Release the mutex that guards the LpcReplyMessage field 00955 // after marking message as being replied to. 00956 // 00957 00958 Msg->RepliedToThread = WakeupThread; 00959 00960 WakeupThread->LpcReplyMessageId = 0; 00961 WakeupThread->LpcReplyMessage = (PVOID)Msg; 00962 00963 // 00964 // Remove the thread from the reply rundown list as we are sending the reply. 00965 // 00966 00967 if ((!WakeupThread->LpcExitThreadCalled) && (!IsListEmpty( &WakeupThread->LpcReplyChain ))) { 00968 00969 RemoveEntryList( &WakeupThread->LpcReplyChain ); 00970 00971 InitializeListHead( &WakeupThread->LpcReplyChain ); 00972 } 00973 00974 if ((CurrentThread->LpcReceivedMsgIdValid) && 00975 (CurrentThread->LpcReceivedMessageId == CapturedReplyMessage.MessageId)) { 00976 00977 CurrentThread->LpcReceivedMessageId = 0; 00978 00979 CurrentThread->LpcReceivedMsgIdValid = FALSE; 00980 } 00981 00982 LpcpTrace(( "%s Waiting for message to Port %x (%s)\n", 00983 PsGetCurrentProcess()->ImageFileName, 00984 ReceivePort, 00985 LpcpGetCreatorName( ReceivePort ))); 00986 00987 LpcpReleaseLpcpLock(); 00988 00989 // 00990 // Wake up the thread that is waiting for an answer to its request 00991 // inside of NtRequestWaitReplyPort or NtReplyWaitReplyPort 00992 // 00993 00994 KeReleaseSemaphore( &WakeupThread->LpcReplySemaphore, 00995 1, 00996 1, 00997 FALSE ); 00998 00999 ObDereferenceObject( WakeupThread ); 01000 01001 // 01002 // **** the timeout on this wait and the next wait appear to be the 01003 // only substantial difference between NtReplyWaitReceivePort 01004 // and NtReplyWaitReceivePortEx 01005 01006 Status = KeWaitForSingleObject( ReceivePort->MsgQueue.Semaphore, 01007 WrLpcReceive, 01008 WaitMode, 01009 FALSE, 01010 Timeout ); 01011 01012 // 01013 // Fall into receive code. Client thread reference will be 01014 // returned by the client when it wakes up. 01015 // 01016 01017 } else { 01018 01019 // 01020 // The user did not give us a reply message to send off 01021 // 01022 // **** it looks like the only reason to have the then and else 01023 // clause both do a wait it to have the lpcp trace denote 01024 // the wait without a preceeding reply 01025 // 01026 // Wait for a message 01027 // 01028 01029 LpcpTrace(( "%s Waiting for message to Port %x (%s)\n", 01030 PsGetCurrentProcess()->ImageFileName, 01031 ReceivePort, 01032 LpcpGetCreatorName( ReceivePort ))); 01033 01034 Status = KeWaitForSingleObject( ReceivePort->MsgQueue.Semaphore, 01035 WrLpcReceive, 01036 WaitMode, 01037 FALSE, 01038 Timeout ); 01039 } 01040 01041 // 01042 // At this point we've awoke from our wait for a receive 01043 // 01044 01045 if (Status == STATUS_SUCCESS) { 01046 01047 LpcpAcquireLpcpLock(); 01048 01049 // 01050 // See if we awoke without a message in our receive port 01051 // 01052 01053 if (IsListEmpty( &ReceivePort->MsgQueue.ReceiveHead )) { 01054 01055 if ( ReceivePort->Flags & PORT_WAITABLE ) { 01056 01057 KeResetEvent( &ReceivePort->WaitEvent ); 01058 } 01059 01060 LpcpReleaseLpcpLock(); 01061 01062 ObDereferenceObject( PortObject ); 01063 01064 return STATUS_UNSUCCESSFUL; 01065 } 01066 01067 // 01068 // We have a message in our recieve port. So let's pull it out 01069 // 01070 01071 Msg = (PLPCP_MESSAGE)RemoveHeadList( &ReceivePort->MsgQueue.ReceiveHead ); 01072 01073 if ( IsListEmpty( &ReceivePort->MsgQueue.ReceiveHead ) ) { 01074 01075 if ( ReceivePort->Flags & PORT_WAITABLE ) { 01076 01077 KeResetEvent( &ReceivePort->WaitEvent ); 01078 } 01079 } 01080 01081 InitializeListHead( &Msg->Entry ); 01082 01083 LpcpTrace(( "%s Receive Msg %lx (%u) from Port %lx (%s)\n", 01084 PsGetCurrentProcess()->ImageFileName, 01085 Msg, 01086 Msg->Request.MessageId, 01087 ReceivePort, 01088 LpcpGetCreatorName( ReceivePort ))); 01089 01090 // 01091 // Now make the thread state to be the message we're currently 01092 // working on 01093 // 01094 01095 CurrentThread->LpcReceivedMessageId = Msg->Request.MessageId; 01096 CurrentThread->LpcReceivedMsgIdValid = TRUE; 01097 01098 LpcpReleaseLpcpLock(); 01099 01100 try { 01101 01102 // 01103 // Check if the message is a connection request 01104 // 01105 01106 if ((Msg->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) == LPC_CONNECTION_REQUEST) { 01107 01108 PLPCP_CONNECTION_MESSAGE ConnectMsg; 01109 ULONG ConnectionInfoLength; 01110 PLPCP_MESSAGE TempMsg; 01111 01112 ConnectMsg = (PLPCP_CONNECTION_MESSAGE)(Msg + 1); 01113 01114 ConnectionInfoLength = Msg->Request.u1.s1.DataLength - sizeof( *ConnectMsg ); 01115 01116 // 01117 // Dont free message until NtAcceptConnectPort called, and if it's never called 01118 // then we'll keep the message until the client exits. 01119 // 01120 01121 TempMsg = Msg; 01122 Msg = NULL; 01123 01124 *ReceiveMessage = TempMsg->Request; 01125 01126 ReceiveMessage->u1.s1.TotalLength = (CSHORT)(sizeof( *ReceiveMessage ) + ConnectionInfoLength); 01127 ReceiveMessage->u1.s1.DataLength = (CSHORT)ConnectionInfoLength; 01128 01129 RtlMoveMemory( ReceiveMessage+1, 01130 ConnectMsg + 1, 01131 ConnectionInfoLength ); 01132 01133 if (ARGUMENT_PRESENT( PortContext )) { 01134 01135 *PortContext = NULL; 01136 } 01137 01138 // 01139 // Check if the message is not a reply 01140 // 01141 01142 } else if ((Msg->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) != LPC_REPLY) { 01143 01144 LpcpMoveMessage( ReceiveMessage, 01145 &Msg->Request, 01146 (&Msg->Request) + 1, 01147 0, 01148 NULL ); 01149 01150 if (ARGUMENT_PRESENT( PortContext )) { 01151 01152 *PortContext = Msg->PortContext; 01153 } 01154 01155 // 01156 // If message contains DataInfo for access via NtRead/WriteRequestData 01157 // then put the message on a list in the communication port and dont 01158 // free it. It will be freed when the server replies to the message. 01159 // 01160 01161 if (Msg->Request.u2.s2.DataInfoOffset != 0) { 01162 01163 LpcpSaveDataInfoMessage( PortObject, Msg ); 01164 Msg = NULL; 01165 } 01166 01167 // 01168 // Otherwise this is a reply message we just recieved 01169 // 01170 01171 } else { 01172 01173 LpcpPrint(( "LPC: Bogus reply message (%08x) in receive queue of connection port %08x\n", 01174 Msg, ReceivePort )); 01175 01176 KdBreakPoint(); 01177 } 01178 01179 } except( EXCEPTION_EXECUTE_HANDLER ) { 01180 01181 Status = GetExceptionCode(); // FIX, FIX 01182 } 01183 01184 // 01185 // Acquire the LPC mutex and decrement the reference count for the 01186 // message. If the reference count goes to zero the message will be 01187 // deleted. 01188 // 01189 01190 if (Msg != NULL) { 01191 01192 LpcpFreeToPortZone( Msg, FALSE ); 01193 } 01194 } 01195 01196 ObDereferenceObject( PortObject ); 01197 01198 // 01199 // And return to our caller 01200 // 01201 01202 return Status; 01203 } }


Generated on Sat May 15 19:44:34 2004 for test by doxygen 1.3.7