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

lpc.h File Reference

Go to the source code of this file.

Classes

struct  _LPCP_NONPAGED_PORT_QUEUE
struct  _LPCP_PORT_QUEUE
struct  _LPCP_PORT_ZONE
struct  _LPCP_PORT_OBJECT
struct  _LPCP_MESSAGE
struct  _LPCP_CONNECTION_MESSAGE

Defines

#define LPCP_ZONE_ALIGNMENT   16
#define LPCP_ZONE_ALIGNMENT_MASK   ~(LPCP_ZONE_ALIGNMENT-1)
#define LPCP_ZONE_MAX_POOL_USAGE   (8*PAGE_SIZE)
#define PORT_TYPE   0x0000000F
#define SERVER_CONNECTION_PORT   0x00000001
#define UNCONNECTED_COMMUNICATION_PORT   0x00000002
#define SERVER_COMMUNICATION_PORT   0x00000003
#define CLIENT_COMMUNICATION_PORT   0x00000004
#define PORT_WAITABLE   0x20000000
#define PORT_NAME_DELETED   0x40000000
#define PORT_DYNAMIC_SECURITY   0x80000000
#define PORT_DELETED   0x10000000

Typedefs

typedef _LPCP_NONPAGED_PORT_QUEUE LPCP_NONPAGED_PORT_QUEUE
typedef _LPCP_NONPAGED_PORT_QUEUEPLPCP_NONPAGED_PORT_QUEUE
typedef _LPCP_PORT_QUEUE LPCP_PORT_QUEUE
typedef _LPCP_PORT_QUEUEPLPCP_PORT_QUEUE
typedef _LPCP_PORT_ZONE LPCP_PORT_ZONE
typedef _LPCP_PORT_ZONEPLPCP_PORT_ZONE
typedef _LPCP_PORT_OBJECT LPCP_PORT_OBJECT
typedef _LPCP_PORT_OBJECTPLPCP_PORT_OBJECT
typedef _LPCP_MESSAGE LPCP_MESSAGE
typedef _LPCP_MESSAGEPLPCP_MESSAGE
typedef _LPCP_CONNECTION_MESSAGE LPCP_CONNECTION_MESSAGE
typedef _LPCP_CONNECTION_MESSAGEPLPCP_CONNECTION_MESSAGE

Functions

BOOLEAN LpcInitSystem (VOID)
VOID LpcExitThread (PETHREAD Thread)
VOID LpcDumpThread (PETHREAD Thread, IN POB_DUMP_CONTROL Control OPTIONAL)
NTKERNELAPI NTSTATUS LpcRequestPort (IN PVOID PortAddress, IN PPORT_MESSAGE RequestMessage)
NTSTATUS LpcRequestWaitReplyPort (IN PVOID PortAddress, IN PPORT_MESSAGE RequestMessage, OUT PPORT_MESSAGE ReplyMessage)

Variables

ULONG LpcCallOperationCount
ULONG LpcCallBackOperationCount
ULONG LpcDatagramOperationCount


Define Documentation

#define CLIENT_COMMUNICATION_PORT   0x00000004
 

Definition at line 134 of file lpc.h.

Referenced by LpcpDeletePort(), LpcpFreePortClientSecurity(), LpcRequestPort(), LpcRequestWaitReplyPort(), NtReplyWaitReceivePort(), NtReplyWaitReceivePortEx(), NtRequestPort(), NtRequestWaitReplyPort(), and NtSecureConnectPort().

#define LPCP_ZONE_ALIGNMENT   16
 

Definition at line 84 of file lpc.h.

Referenced by LpcInitSystem().

#define LPCP_ZONE_ALIGNMENT_MASK   ~(LPCP_ZONE_ALIGNMENT-1)
 

Definition at line 85 of file lpc.h.

Referenced by LpcInitSystem().

#define LPCP_ZONE_MAX_POOL_USAGE   (8*PAGE_SIZE)
 

Definition at line 91 of file lpc.h.

Referenced by LpcInitSystem().

#define PORT_DELETED   0x10000000
 

Definition at line 138 of file lpc.h.

Referenced by NtImpersonateClientOfPort(), NtRequestPort(), and ObfDereferenceObject().

#define PORT_DYNAMIC_SECURITY   0x80000000
 

Definition at line 137 of file lpc.h.

Referenced by LpcpFreePortClientSecurity(), NtImpersonateClientOfPort(), and NtSecureConnectPort().

#define PORT_NAME_DELETED   0x40000000
 

Definition at line 136 of file lpc.h.

Referenced by LpcpDestroyPortQueue(), and NtSecureConnectPort().

#define PORT_TYPE   0x0000000F
 

Definition at line 130 of file lpc.h.

Referenced by LpcpClosePort(), LpcpDeletePort(), LpcpDestroyPortQueue(), LpcpFindDataInfoMessage(), LpcpFreeDataInfoMessage(), LpcpFreePortClientSecurity(), LpcpSaveDataInfoMessage(), LpcRequestPort(), LpcRequestWaitReplyPort(), NtCompleteConnectPort(), NtImpersonateClientOfPort(), NtReplyWaitReceivePort(), NtReplyWaitReceivePortEx(), NtRequestPort(), NtRequestWaitReplyPort(), and NtSecureConnectPort().

#define PORT_WAITABLE   0x20000000
 

Definition at line 135 of file lpc.h.

Referenced by LpcpCreatePort(), LpcRequestPort(), LpcRequestWaitReplyPort(), NtReplyWaitReceivePort(), NtReplyWaitReceivePortEx(), NtRequestPort(), NtRequestWaitReplyPort(), and NtSecureConnectPort().

#define SERVER_COMMUNICATION_PORT   0x00000003
 

Definition at line 133 of file lpc.h.

Referenced by LpcpDeletePort(), LpcRequestPort(), LpcRequestWaitReplyPort(), NtAcceptConnectPort(), NtCompleteConnectPort(), NtImpersonateClientOfPort(), NtRequestPort(), and NtRequestWaitReplyPort().

#define SERVER_CONNECTION_PORT   0x00000001
 

Definition at line 131 of file lpc.h.

Referenced by LpcpClosePort(), LpcpCreatePort(), LpcpDeletePort(), LpcpDestroyPortQueue(), LpcRequestPort(), LpcRequestWaitReplyPort(), NtRequestPort(), NtRequestWaitReplyPort(), and NtSecureConnectPort().

#define UNCONNECTED_COMMUNICATION_PORT   0x00000002
 

Definition at line 132 of file lpc.h.

Referenced by LpcpCreatePort(), LpcpFindDataInfoMessage(), LpcpFreeDataInfoMessage(), and LpcpSaveDataInfoMessage().


Typedef Documentation

typedef struct _LPCP_CONNECTION_MESSAGE LPCP_CONNECTION_MESSAGE
 

typedef struct _LPCP_MESSAGE LPCP_MESSAGE
 

typedef struct _LPCP_NONPAGED_PORT_QUEUE LPCP_NONPAGED_PORT_QUEUE
 

typedef struct _LPCP_PORT_OBJECT LPCP_PORT_OBJECT
 

Referenced by LpcpCreatePort(), NtAcceptConnectPort(), and NtSecureConnectPort().

typedef struct _LPCP_PORT_QUEUE LPCP_PORT_QUEUE
 

typedef struct _LPCP_PORT_ZONE LPCP_PORT_ZONE
 

typedef struct _LPCP_CONNECTION_MESSAGE * PLPCP_CONNECTION_MESSAGE
 

typedef struct _LPCP_MESSAGE * PLPCP_MESSAGE
 

typedef struct _LPCP_NONPAGED_PORT_QUEUE * PLPCP_NONPAGED_PORT_QUEUE
 

typedef struct _LPCP_PORT_OBJECT * PLPCP_PORT_OBJECT
 

typedef struct _LPCP_PORT_QUEUE * PLPCP_PORT_QUEUE
 

typedef struct _LPCP_PORT_ZONE * PLPCP_PORT_ZONE
 


Function Documentation

VOID LpcDumpThread PETHREAD  Thread,
IN POB_DUMP_CONTROL Control  OPTIONAL
 

VOID LpcExitThread PETHREAD  Thread  ) 
 

Definition at line 281 of file lpcclose.c.

References _LPCP_MESSAGE::Entry, _ETHREAD::LpcExitThreadCalled, LpcpAcquireLpcpLock, LpcpFreeToPortZone(), LpcpReleaseLpcpLock, LpcpTrace, _ETHREAD::LpcReplyChain, _ETHREAD::LpcReplyMessage, _ETHREAD::LpcReplyMessageId, NULL, ObDereferenceObject, _LPCP_MESSAGE::RepliedToThread, and TRUE.

Referenced by PspExitThread().

00287 : 00288 00289 This routine is called whenever a thread is exiting and need to cleanup the 00290 lpc port for the thread. 00291 00292 Arguments: 00293 00294 Thread - Supplies the thread being terminated 00295 00296 Return Value: 00297 00298 None. 00299 00300 --*/ 00301 00302 { 00303 PLPCP_MESSAGE Msg; 00304 00305 // 00306 // Acquire the mutex that protects the LpcReplyMessage field of 00307 // the thread. Zero the field so nobody else tries to process it 00308 // when we release the lock. 00309 // 00310 00311 LpcpAcquireLpcpLock(); 00312 00313 if (!IsListEmpty( &Thread->LpcReplyChain )) { 00314 00315 RemoveEntryList( &Thread->LpcReplyChain ); 00316 } 00317 00318 // 00319 // Indicate that this thread is exiting 00320 // 00321 00322 Thread->LpcExitThreadCalled = TRUE; 00323 Thread->LpcReplyMessageId = 0; 00324 00325 // 00326 // If we need to reply to a message then if the thread that we need to reply 00327 // to is still around we want to dereference the thread and free the message 00328 // 00329 00330 Msg = Thread->LpcReplyMessage; 00331 00332 if (Msg != NULL) { 00333 00334 Thread->LpcReplyMessage = NULL; 00335 00336 if (Msg->RepliedToThread != NULL) { 00337 00338 ObDereferenceObject( Msg->RepliedToThread ); 00339 00340 Msg->RepliedToThread = NULL; 00341 } 00342 00343 LpcpTrace(( "Cleanup Msg %lx (%d) for Thread %lx allocated\n", Msg, IsListEmpty( &Msg->Entry ), Thread )); 00344 00345 LpcpFreeToPortZone( Msg, TRUE ); 00346 } 00347 00348 // 00349 // Free the global lpc lock 00350 // 00351 00352 LpcpReleaseLpcpLock(); 00353 00354 // 00355 // And return to our caller 00356 // 00357 00358 return; 00359 } }

BOOLEAN LpcInitSystem VOID   ) 
 

Definition at line 76 of file lpcinit.c.

References FALSE, L, LPCP_ZONE_ALIGNMENT, LPCP_ZONE_ALIGNMENT_MASK, LPCP_ZONE_MAX_POOL_USAGE, LpcpClosePort(), LpcpDeletePort(), LpcpInitializeLpcpLock, LpcpInitializePortZone(), LpcpNextCallbackId, LpcpNextMessageId, LpcPortObjectType, LpcpPortMapping, LpcWaitablePortObjectType, NonPagedPool, NT_SUCCESS, NTSTATUS(), NULL, ObCreateObjectType(), PAGE_SIZE, PagedPool, RtlInitUnicodeString(), Status, and TRUE.

00082 : 00083 00084 This function performs the system initialization for the LPC package. 00085 LPC stands for Local Inter-Process Communication. 00086 00087 Arguments: 00088 00089 None. 00090 00091 Return Value: 00092 00093 TRUE if successful and FALSE if an error occurred. 00094 00095 The following errors can occur: 00096 00097 - insufficient memory 00098 00099 --*/ 00100 00101 { 00102 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; 00103 UNICODE_STRING PortTypeName; 00104 ULONG ZoneElementSize; 00105 NTSTATUS Status; 00106 00107 // 00108 // Initialize our global lpc lock 00109 // 00110 00111 LpcpInitializeLpcpLock(); 00112 00113 // 00114 // Create the object type for the port object 00115 // 00116 00117 RtlInitUnicodeString( &PortTypeName, L"Port" ); 00118 00119 RtlZeroMemory( &ObjectTypeInitializer, sizeof( ObjectTypeInitializer )); 00120 00121 ObjectTypeInitializer.Length = sizeof( ObjectTypeInitializer ); 00122 ObjectTypeInitializer.GenericMapping = LpcpPortMapping; 00123 ObjectTypeInitializer.MaintainTypeList = TRUE; 00124 ObjectTypeInitializer.PoolType = PagedPool; 00125 ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof( LPCP_PORT_OBJECT ); 00126 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof( LPCP_NONPAGED_PORT_QUEUE ); 00127 ObjectTypeInitializer.InvalidAttributes = OBJ_VALID_ATTRIBUTES ^ PORT_VALID_OBJECT_ATTRIBUTES; 00128 ObjectTypeInitializer.ValidAccessMask = PORT_ALL_ACCESS; 00129 ObjectTypeInitializer.CloseProcedure = LpcpClosePort; 00130 ObjectTypeInitializer.DeleteProcedure = LpcpDeletePort; 00131 ObjectTypeInitializer.UseDefaultObject = TRUE ; 00132 00133 ObCreateObjectType( &PortTypeName, 00134 &ObjectTypeInitializer, 00135 (PSECURITY_DESCRIPTOR)NULL, 00136 &LpcPortObjectType ); 00137 00138 // 00139 // Create the object type for the waitable port object 00140 // 00141 00142 RtlInitUnicodeString( &PortTypeName, L"WaitablePort" ); 00143 ObjectTypeInitializer.PoolType = NonPagedPool ; 00144 ObjectTypeInitializer.UseDefaultObject = FALSE ; 00145 00146 ObCreateObjectType( &PortTypeName, 00147 &ObjectTypeInitializer, 00148 (PSECURITY_DESCRIPTOR)NULL, 00149 &LpcWaitablePortObjectType ); 00150 00151 // 00152 // Initialize the lpc message and callback id counters 00153 // 00154 00155 LpcpNextMessageId = 1; 00156 LpcpNextCallbackId = 1; 00157 00158 // 00159 // Initialize the lpc port zone. Each element can contain a max 00160 // message, plus an LPCP message structure, plus an LPCP connection 00161 // message 00162 // 00163 00164 ZoneElementSize = PORT_MAXIMUM_MESSAGE_LENGTH + 00165 sizeof( LPCP_MESSAGE ) + 00166 sizeof( LPCP_CONNECTION_MESSAGE ); 00167 00168 // 00169 // Round up the size to the next 16 byte alignment 00170 // 00171 00172 ZoneElementSize = (ZoneElementSize + LPCP_ZONE_ALIGNMENT - 1) & 00173 LPCP_ZONE_ALIGNMENT_MASK; 00174 00175 // 00176 // Initialize the zone 00177 // 00178 00179 Status = LpcpInitializePortZone( ZoneElementSize, 00180 PAGE_SIZE, 00181 LPCP_ZONE_MAX_POOL_USAGE ); 00182 00183 if (!NT_SUCCESS( Status )) { 00184 00185 return( FALSE ); 00186 } 00187 00188 return( TRUE ); 00189 }

NTKERNELAPI NTSTATUS LpcRequestPort IN PVOID  PortAddress,
IN PPORT_MESSAGE  RequestMessage
 

Definition at line 1181 of file lpcsend.c.

References CLIENT_COMMUNICATION_PORT, _LPCP_PORT_OBJECT::ConnectedPort, _LPCP_PORT_OBJECT::ConnectionPort, _LPCP_MESSAGE::Entry, FALSE, _LPCP_PORT_OBJECT::Flags, KeEnterCriticalRegion, KeLeaveCriticalRegion, KeReleaseSemaphore(), KernelMode, KeSetEvent(), KPROCESSOR_MODE, L, LPC_RELEASE_WAIT_INCREMENT, LpcpAcquireLpcpLock, LpcpAllocateFromPortZone(), LpcpFreeToPortZone(), LpcpGenerateMessageId, LpcpGetCreatorName(), LpcpMoveMessage(), LpcpReleaseLpcpLock, LpcpTrace, _LPCP_PORT_OBJECT::MaxMessageLength, _LPCP_PORT_OBJECT::MsgQueue, NULL, PAGED_CODE, PORT_TYPE, PORT_WAITABLE, _LPCP_MESSAGE::PortContext, _LPCP_PORT_OBJECT::PortContext, PsGetCurrentProcess, PsGetCurrentThread, _LPCP_PORT_QUEUE::ReceiveHead, _LPCP_MESSAGE::RepliedToThread, _LPCP_MESSAGE::Request, RequestMessage, _LPCP_PORT_QUEUE::Semaphore, SERVER_COMMUNICATION_PORT, SERVER_CONNECTION_PORT, TRUE, and _LPCP_PORT_OBJECT::WaitEvent.

Referenced by LpcpDeletePort(), PspExitThread(), and xxxActivateDebugger().

01188 : 01189 01190 This procedure is similar to NtRequestPort but without the Handle based 01191 interface. 01192 01193 Arguments: 01194 01195 PortAddress - Supplies a pointer to the communication port to send 01196 the request message to. 01197 01198 RequestMessage - Specifies a pointer to the request message. The Type 01199 field of the message is set to LPC_DATAGRAM by the service. 01200 01201 Return Value: 01202 01203 NTSTATUS - A status code that indicates whether or not the operation was 01204 successful. 01205 01206 --*/ 01207 01208 { 01209 PLPCP_PORT_OBJECT PortObject = (PLPCP_PORT_OBJECT)PortAddress; 01210 PLPCP_PORT_OBJECT QueuePort; 01211 ULONG MsgType; 01212 PLPCP_MESSAGE Msg; 01213 KPROCESSOR_MODE PreviousMode; 01214 01215 PAGED_CODE(); 01216 01217 // 01218 // Get previous processor mode and validate parameters 01219 // 01220 01221 PreviousMode = KeGetPreviousMode(); 01222 01223 if (RequestMessage->u2.s2.Type != 0) { 01224 01225 MsgType = RequestMessage->u2.s2.Type & ~LPC_KERNELMODE_MESSAGE; 01226 01227 if ((MsgType < LPC_DATAGRAM) || 01228 (MsgType > LPC_CLIENT_DIED)) { 01229 01230 return STATUS_INVALID_PARAMETER; 01231 } 01232 01233 // 01234 // If previous mode is kernel, allow the LPC_KERNELMODE_MESSAGE 01235 // bit to be passed in message type field. 01236 // 01237 01238 if ((PreviousMode == KernelMode) && 01239 (RequestMessage->u2.s2.Type & LPC_KERNELMODE_MESSAGE)) { 01240 01241 MsgType |= LPC_KERNELMODE_MESSAGE; 01242 } 01243 01244 } else { 01245 01246 MsgType = LPC_DATAGRAM; 01247 } 01248 01249 if (RequestMessage->u2.s2.DataInfoOffset != 0) { 01250 01251 return STATUS_INVALID_PARAMETER; 01252 } 01253 01254 // 01255 // Validate the message length 01256 // 01257 01258 if (((ULONG)RequestMessage->u1.s1.TotalLength > PortObject->MaxMessageLength) || 01259 ((ULONG)RequestMessage->u1.s1.TotalLength <= (ULONG)RequestMessage->u1.s1.DataLength)) { 01260 01261 return STATUS_PORT_MESSAGE_TOO_LONG; 01262 } 01263 01264 // 01265 // Allocate a message block 01266 // 01267 01268 LpcpAcquireLpcpLock(); 01269 01270 Msg = (PLPCP_MESSAGE)LpcpAllocateFromPortZone( RequestMessage->u1.s1.TotalLength ); 01271 01272 LpcpReleaseLpcpLock(); 01273 01274 if (Msg == NULL) { 01275 01276 return STATUS_NO_MEMORY; 01277 } 01278 01279 // 01280 // Fill in the message block. 01281 // 01282 01283 Msg->RepliedToThread = NULL; 01284 Msg->PortContext = NULL; 01285 01286 LpcpMoveMessage( &Msg->Request, 01287 RequestMessage, 01288 (RequestMessage + 1), 01289 MsgType, 01290 &PsGetCurrentThread()->Cid ); 01291 01292 // 01293 // Acquire the global Lpc mutex that guards the LpcReplyMessage 01294 // field of the thread and the request message queue. Stamp the 01295 // request message with a serial number, insert the message at 01296 // the tail of the request message queue 01297 // 01298 // This all needs to be performed with APCs disabled to avoid 01299 // the situation where something gets put on the queue and this 01300 // thread gets suspended before being able to release the semaphore. 01301 // 01302 01303 KeEnterCriticalRegion(); 01304 01305 LpcpAcquireLpcpLock(); 01306 01307 if ((PortObject->Flags & PORT_TYPE) != SERVER_CONNECTION_PORT) { 01308 01309 QueuePort = PortObject->ConnectedPort; 01310 01311 if (QueuePort != NULL) { 01312 01313 if ((PortObject->Flags & PORT_TYPE) == CLIENT_COMMUNICATION_PORT) { 01314 01315 Msg->PortContext = QueuePort->PortContext; 01316 QueuePort = PortObject->ConnectionPort; 01317 01318 // 01319 // **** this test and assignment are bogus because we earlier 01320 // unconditionally set the QueuePort value 01321 // 01322 01323 } else if ((PortObject->Flags & PORT_TYPE) != SERVER_COMMUNICATION_PORT) { 01324 01325 QueuePort = PortObject->ConnectionPort; 01326 } 01327 } 01328 01329 } else { 01330 01331 QueuePort = PortObject; 01332 } 01333 01334 // 01335 // At this point we have an LPC message ready to send and if queue port is 01336 // not null then we have a port to actually send the message off to 01337 // 01338 01339 if (QueuePort != NULL) { 01340 01341 Msg->Request.MessageId = LpcpGenerateMessageId(); 01342 Msg->Request.CallbackId = 0; 01343 01344 PsGetCurrentThread()->LpcReplyMessageId = 0; 01345 01346 InsertTailList( &QueuePort->MsgQueue.ReceiveHead, &Msg->Entry ); 01347 01348 LpcpTrace(( "%s Send DataGram (%s) Msg %lx [%08x %08x %08x %08x] to Port %lx (%s)\n", 01349 PsGetCurrentProcess()->ImageFileName, 01350 LpcpMessageTypeName[ Msg->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE ], 01351 Msg, 01352 *((PULONG)(Msg+1)+0), 01353 *((PULONG)(Msg+1)+1), 01354 *((PULONG)(Msg+1)+2), 01355 *((PULONG)(Msg+1)+3), 01356 QueuePort, 01357 LpcpGetCreatorName( QueuePort ))); 01358 01359 // 01360 // Release the mutex, increment the request message queue 01361 // semaphore by one for the newly inserted request message, 01362 // then exit the critical region. 01363 // 01364 01365 LpcpReleaseLpcpLock(); 01366 01367 KeReleaseSemaphore( QueuePort->MsgQueue.Semaphore, 01368 LPC_RELEASE_WAIT_INCREMENT, 01369 1L, 01370 FALSE ); 01371 01372 01373 if ( QueuePort->Flags & PORT_WAITABLE ) { 01374 01375 KeSetEvent( &QueuePort->WaitEvent, 01376 LPC_RELEASE_WAIT_INCREMENT, 01377 FALSE ); 01378 } 01379 01380 KeLeaveCriticalRegion(); 01381 01382 return STATUS_SUCCESS; 01383 01384 } 01385 01386 // 01387 // At this point we have a message but not a valid port to queue it off 01388 // to so we'll release the unused message, release our lock and enable 01389 // APC again 01390 // 01391 01392 LpcpFreeToPortZone( Msg, TRUE ); 01393 01394 LpcpReleaseLpcpLock(); 01395 01396 KeLeaveCriticalRegion(); 01397 01398 // 01399 // And return the error status to our caller 01400 // 01401 01402 return STATUS_PORT_DISCONNECTED; 01403 }

NTSTATUS LpcRequestWaitReplyPort IN PVOID  PortAddress,
IN PPORT_MESSAGE  RequestMessage,
OUT PPORT_MESSAGE  ReplyMessage
 

Definition at line 1407 of file lpcsend.c.

References _ETHREAD::Cid, CLIENT_COMMUNICATION_PORT, _LPCP_PORT_OBJECT::ConnectedPort, _LPCP_PORT_OBJECT::ConnectionPort, _LPCP_MESSAGE::Entry, FALSE, _LPCP_PORT_OBJECT::Flags, KeReadStateSemaphore(), KeReleaseSemaphore(), KernelMode, KeSetEvent(), KeWaitForSingleObject(), KPROCESSOR_MODE, LPC_RELEASE_WAIT_INCREMENT, _ETHREAD::LpcExitThreadCalled, LpcpAcquireLpcpLock, LpcpAllocateFromPortZone(), LpcpFreeToPortZone(), LpcpGenerateCallbackId, LpcpGenerateMessageId, LpcpGetCreatorName(), LpcpMoveMessage(), LpcpReleaseLpcpLock, LpcpTrace, _ETHREAD::LpcReplyChain, _LPCP_PORT_OBJECT::LpcReplyChainHead, _ETHREAD::LpcReplyMessage, _ETHREAD::LpcReplyMessageId, _ETHREAD::LpcReplySemaphore, _LPCP_PORT_OBJECT::MaxMessageLength, _LPCP_PORT_OBJECT::MsgQueue, NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObject, PAGED_CODE, PORT_TYPE, PORT_WAITABLE, _LPCP_MESSAGE::PortContext, _LPCP_PORT_OBJECT::PortContext, PsGetCurrentProcess, PsGetCurrentThread, PsLookupProcessThreadByCid(), _LPCP_PORT_QUEUE::ReceiveHead, _LPCP_MESSAGE::RepliedToThread, ReplyMessage(), _LPCP_MESSAGE::Request, RequestMessage, _LPCP_PORT_QUEUE::Semaphore, SERVER_COMMUNICATION_PORT, SERVER_CONNECTION_PORT, Status, THREAD_TO_PROCESS, TRUE, _LPCP_PORT_OBJECT::WaitEvent, WrExecutive, and WrLpcReply.

Referenced by DbgkpSendApiMessage(), ExpRaiseHardError(), and IopSendMessageToTrackService().

01415 : 01416 01417 This procedure is similar to NtRequestWaitReplyPort but without the 01418 handle based interface 01419 01420 Arguments: 01421 01422 PortAddress - Supplies the communication port object to send the 01423 request message to. 01424 01425 RequestMessage - Specifies a pointer to a request message to send. 01426 01427 ReplyMessage - Specifies the address of a variable that will receive the 01428 reply message. This parameter may point to the same buffer as the 01429 RequestMessage parameter. 01430 01431 Return Value: 01432 01433 NTSTATUS - A status code that indicates whether or not the operation was 01434 successful. 01435 01436 --*/ 01437 01438 { 01439 PLPCP_PORT_OBJECT PortObject = (PLPCP_PORT_OBJECT)PortAddress; 01440 PLPCP_PORT_OBJECT QueuePort; 01441 PLPCP_PORT_OBJECT RundownPort; 01442 PKSEMAPHORE ReleaseSemaphore; 01443 NTSTATUS Status; 01444 ULONG MsgType; 01445 PLPCP_MESSAGE Msg; 01446 PETHREAD CurrentThread; 01447 PETHREAD WakeupThread; 01448 BOOLEAN CallbackRequest; 01449 KPROCESSOR_MODE PreviousMode; 01450 01451 PAGED_CODE(); 01452 01453 CurrentThread = PsGetCurrentThread(); 01454 01455 if (CurrentThread->LpcExitThreadCalled) { 01456 01457 return STATUS_THREAD_IS_TERMINATING; 01458 } 01459 01460 // 01461 // Get previous processor mode and validate parameters 01462 // 01463 01464 PreviousMode = KeGetPreviousMode(); 01465 MsgType = RequestMessage->u2.s2.Type & ~LPC_KERNELMODE_MESSAGE; 01466 CallbackRequest = FALSE; 01467 01468 switch (MsgType) { 01469 01470 case 0: 01471 01472 MsgType = LPC_REQUEST; 01473 break; 01474 01475 case LPC_REQUEST: 01476 01477 CallbackRequest = TRUE; 01478 break; 01479 01480 case LPC_CLIENT_DIED: 01481 case LPC_PORT_CLOSED: 01482 case LPC_EXCEPTION: 01483 case LPC_DEBUG_EVENT: 01484 case LPC_ERROR_EVENT: 01485 01486 break; 01487 01488 default : 01489 01490 return STATUS_INVALID_PARAMETER; 01491 } 01492 01493 // 01494 // Allow the LPC_KERNELMODE_MESSAGE 01495 // bit to be passed in message type field. Don't check the previous mode !!! 01496 // 01497 01498 if ( RequestMessage->u2.s2.Type & LPC_KERNELMODE_MESSAGE) { 01499 01500 MsgType |= LPC_KERNELMODE_MESSAGE; 01501 } 01502 01503 RequestMessage->u2.s2.Type = (CSHORT)MsgType; 01504 01505 // 01506 // Validate the message length 01507 // 01508 01509 if (((ULONG)RequestMessage->u1.s1.TotalLength > PortObject->MaxMessageLength) || 01510 ((ULONG)RequestMessage->u1.s1.TotalLength <= (ULONG)RequestMessage->u1.s1.DataLength)) { 01511 01512 return STATUS_PORT_MESSAGE_TOO_LONG; 01513 } 01514 01515 // 01516 // Determine which port to queue the message to and get client 01517 // port context if client sending to server. Also validate 01518 // length of message being sent. 01519 // 01520 01521 LpcpAcquireLpcpLock(); 01522 01523 Msg = (PLPCP_MESSAGE)LpcpAllocateFromPortZone( RequestMessage->u1.s1.TotalLength ); 01524 01525 LpcpReleaseLpcpLock(); 01526 01527 if (Msg == NULL) { 01528 01529 return STATUS_NO_MEMORY; 01530 } 01531 01532 if (CallbackRequest) { 01533 01534 // 01535 // Check for a valid request message id 01536 // 01537 01538 if (RequestMessage->MessageId == 0) { 01539 01540 LpcpFreeToPortZone( Msg, FALSE ); 01541 01542 return STATUS_INVALID_PARAMETER; 01543 } 01544 01545 // 01546 // Translate the ClientId from the request into a 01547 // thread pointer. This is a referenced pointer to keep the thread 01548 // from evaporating out from under us. 01549 // 01550 01551 Status = PsLookupProcessThreadByCid( &RequestMessage->ClientId, 01552 NULL, 01553 &WakeupThread ); 01554 01555 if (!NT_SUCCESS( Status )) { 01556 01557 LpcpFreeToPortZone( Msg, FALSE ); 01558 01559 return Status; 01560 } 01561 01562 // 01563 // Acquire the mutex that gaurds the LpcReplyMessage field of 01564 // the thread and get the pointer to the message that the thread 01565 // is waiting for a reply to. 01566 // 01567 01568 LpcpAcquireLpcpLock(); 01569 01570 // 01571 // See if the thread is waiting for a reply to the message 01572 // specified on this call. If not then a bogus message 01573 // has been specified, so release the mutex, dereference the thread 01574 // and return failure. 01575 // 01576 01577 if ((WakeupThread->LpcReplyMessageId != RequestMessage->MessageId) 01578 01579 || 01580 01581 ((WakeupThread->LpcReplyMessage != NULL) && 01582 (((PLPCP_MESSAGE)(WakeupThread->LpcReplyMessage))->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) != LPC_REQUEST)) { 01583 01584 LpcpFreeToPortZone( Msg, TRUE ); 01585 01586 LpcpReleaseLpcpLock(); 01587 01588 ObDereferenceObject( WakeupThread ); 01589 01590 return STATUS_REPLY_MESSAGE_MISMATCH; 01591 } 01592 01593 QueuePort = NULL; 01594 Msg->PortContext = NULL; 01595 01596 if ((PortObject->Flags & PORT_TYPE) == SERVER_CONNECTION_PORT) { 01597 01598 RundownPort = PortObject; 01599 01600 } else { 01601 01602 RundownPort = PortObject->ConnectedPort; 01603 01604 if (RundownPort == NULL) { 01605 01606 LpcpFreeToPortZone( Msg, TRUE ); 01607 01608 LpcpReleaseLpcpLock(); 01609 01610 ObDereferenceObject( WakeupThread ); 01611 01612 return STATUS_PORT_DISCONNECTED; 01613 } 01614 01615 if ((PortObject->Flags & PORT_TYPE) == CLIENT_COMMUNICATION_PORT) { 01616 01617 Msg->PortContext = RundownPort->PortContext; 01618 } 01619 } 01620 01621 // 01622 // Allocate and initialize a request message 01623 // 01624 01625 LpcpMoveMessage( &Msg->Request, 01626 RequestMessage, 01627 (RequestMessage + 1), 01628 0, 01629 &CurrentThread->Cid ); 01630 01631 Msg->Request.CallbackId = LpcpGenerateCallbackId(); 01632 01633 LpcpTrace(( "%s CallBack Request (%s) Msg %lx (%u.%u) [%08x %08x %08x %08x] to Thread %lx (%s)\n", 01634 PsGetCurrentProcess()->ImageFileName, 01635 LpcpMessageTypeName[ Msg->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE ], 01636 Msg, 01637 Msg->Request.MessageId, 01638 Msg->Request.CallbackId, 01639 *((PULONG)(Msg+1)+0), 01640 *((PULONG)(Msg+1)+1), 01641 *((PULONG)(Msg+1)+2), 01642 *((PULONG)(Msg+1)+3), 01643 WakeupThread, 01644 THREAD_TO_PROCESS( WakeupThread )->ImageFileName )); 01645 01646 // 01647 // Add an extra reference so LpcExitThread does not evaporate 01648 // the pointer before we get to the wait below 01649 // 01650 01651 ObReferenceObject( WakeupThread ); 01652 01653 Msg->RepliedToThread = WakeupThread; 01654 01655 WakeupThread->LpcReplyMessageId = 0; 01656 WakeupThread->LpcReplyMessage = (PVOID)Msg; 01657 01658 // 01659 // Remove the thread from the reply rundown list as we are sending a callback 01660 // 01661 01662 if (!IsListEmpty( &WakeupThread->LpcReplyChain )) { 01663 01664 RemoveEntryList( &WakeupThread->LpcReplyChain ); 01665 01666 InitializeListHead( &WakeupThread->LpcReplyChain ); 01667 } 01668 01669 CurrentThread->LpcReplyMessageId = Msg->Request.MessageId; 01670 CurrentThread->LpcReplyMessage = NULL; 01671 01672 InsertTailList( &RundownPort->LpcReplyChainHead, &CurrentThread->LpcReplyChain ); 01673 01674 LpcpReleaseLpcpLock(); 01675 01676 // 01677 // Wake up the thread that is waiting for an answer to its request 01678 // inside of NtRequestWaitReplyPort or NtReplyWaitReplyPort 01679 // 01680 01681 ReleaseSemaphore = &WakeupThread->LpcReplySemaphore; 01682 01683 } else { 01684 01685 // 01686 // There is no callbreak requested 01687 // 01688 01689 LpcpMoveMessage( &Msg->Request, 01690 RequestMessage, 01691 (RequestMessage + 1), 01692 0, 01693 &CurrentThread->Cid ); 01694 01695 // 01696 // Acquire the global Lpc mutex that gaurds the LpcReplyMessage 01697 // field of the thread and the request message queue. Stamp the 01698 // request message with a serial number, insert the message at 01699 // the tail of the request message queue and remember the address 01700 // of the message in the LpcReplyMessage field for the current thread. 01701 // 01702 01703 LpcpAcquireLpcpLock(); 01704 01705 Msg->PortContext = NULL; 01706 01707 if ((PortObject->Flags & PORT_TYPE) != SERVER_CONNECTION_PORT) { 01708 01709 QueuePort = PortObject->ConnectedPort; 01710 01711 if (QueuePort == NULL) { 01712 01713 LpcpFreeToPortZone( Msg, TRUE ); 01714 01715 LpcpReleaseLpcpLock(); 01716 01717 return STATUS_PORT_DISCONNECTED; 01718 } 01719 01720 RundownPort = QueuePort; 01721 01722 if ((PortObject->Flags & PORT_TYPE) == CLIENT_COMMUNICATION_PORT) { 01723 01724 Msg->PortContext = QueuePort->PortContext; 01725 QueuePort = PortObject->ConnectionPort; 01726 01727 } else if ((PortObject->Flags & PORT_TYPE) != SERVER_COMMUNICATION_PORT) { 01728 01729 QueuePort = PortObject->ConnectionPort; 01730 } 01731 01732 } else { 01733 01734 QueuePort = PortObject; 01735 RundownPort = PortObject; 01736 } 01737 01738 Msg->RepliedToThread = NULL; 01739 Msg->Request.MessageId = LpcpGenerateMessageId(); 01740 Msg->Request.CallbackId = 0; 01741 01742 CurrentThread->LpcReplyMessageId = Msg->Request.MessageId; 01743 CurrentThread->LpcReplyMessage = NULL; 01744 01745 InsertTailList( &QueuePort->MsgQueue.ReceiveHead, &Msg->Entry ); 01746 InsertTailList( &RundownPort->LpcReplyChainHead, &CurrentThread->LpcReplyChain ); 01747 01748 LpcpTrace(( "%s Send Request (%s) Msg %lx (%u) [%08x %08x %08x %08x] to Port %lx (%s)\n", 01749 PsGetCurrentProcess()->ImageFileName, 01750 LpcpMessageTypeName[ Msg->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE ], 01751 Msg, 01752 Msg->Request.MessageId, 01753 *((PULONG)(Msg+1)+0), 01754 *((PULONG)(Msg+1)+1), 01755 *((PULONG)(Msg+1)+2), 01756 *((PULONG)(Msg+1)+3), 01757 QueuePort, 01758 LpcpGetCreatorName( QueuePort ))); 01759 01760 LpcpReleaseLpcpLock(); 01761 01762 // 01763 // Increment the request message queue semaphore by one for 01764 // the newly inserted request message. Release the spin 01765 // lock, while remaining at the dispatcher IRQL. Then wait for the 01766 // reply to this request by waiting on the LpcReplySemaphore 01767 // for the current thread. 01768 // 01769 01770 ReleaseSemaphore = QueuePort->MsgQueue.Semaphore; 01771 01772 if ( QueuePort->Flags & PORT_WAITABLE ) { 01773 01774 KeSetEvent( &QueuePort->WaitEvent, 01775 LPC_RELEASE_WAIT_INCREMENT, 01776 FALSE ); 01777 } 01778 } 01779 01780 // 01781 // At this point we've enqueued our request and if necessary 01782 // set ourselves up for the callback or reply. 01783 // 01784 // So now wake up the other end 01785 // 01786 01787 Status = KeReleaseSemaphore( ReleaseSemaphore, 01788 1, 01789 1, 01790 FALSE ); 01791 01792 if (CallbackRequest) { 01793 01794 ObDereferenceObject( WakeupThread ); 01795 } 01796 01797 // 01798 // And wait for a reply 01799 // 01800 01801 Status = KeWaitForSingleObject( &CurrentThread->LpcReplySemaphore, 01802 WrLpcReply, 01803 KernelMode, 01804 FALSE, 01805 NULL ); 01806 01807 if (Status == STATUS_USER_APC) { 01808 01809 // 01810 // if the semaphore is signaled, then clear it 01811 // 01812 01813 if (KeReadStateSemaphore( &CurrentThread->LpcReplySemaphore )) { 01814 01815 KeWaitForSingleObject( &CurrentThread->LpcReplySemaphore, 01816 WrExecutive, 01817 KernelMode, 01818 FALSE, 01819 NULL ); 01820 01821 Status = STATUS_SUCCESS; 01822 } 01823 } 01824 01825 // 01826 // Acquire the LPC mutex. Remove the reply message from the current thread 01827 // 01828 01829 LpcpAcquireLpcpLock(); 01830 01831 Msg = CurrentThread->LpcReplyMessage; 01832 01833 CurrentThread->LpcReplyMessage = NULL; 01834 CurrentThread->LpcReplyMessageId = 0; 01835 01836 // 01837 // Remove the thread from the reply rundown list in case we did not wakeup due to 01838 // a reply 01839 // 01840 01841 if (!IsListEmpty( &CurrentThread->LpcReplyChain )) { 01842 01843 RemoveEntryList( &CurrentThread->LpcReplyChain ); 01844 01845 InitializeListHead( &CurrentThread->LpcReplyChain ); 01846 } 01847 01848 #if DBG 01849 if (Msg != NULL) { 01850 01851 LpcpTrace(( "%s Got Reply Msg %lx (%u) [%08x %08x %08x %08x] for Thread %lx (%s)\n", 01852 PsGetCurrentProcess()->ImageFileName, 01853 Msg, 01854 Msg->Request.MessageId, 01855 *((PULONG)(Msg+1)+0), 01856 *((PULONG)(Msg+1)+1), 01857 *((PULONG)(Msg+1)+2), 01858 *((PULONG)(Msg+1)+3), 01859 CurrentThread, 01860 THREAD_TO_PROCESS( CurrentThread )->ImageFileName )); 01861 } 01862 #endif 01863 01864 LpcpReleaseLpcpLock(); 01865 01866 // 01867 // If the wait succeeded, copy the reply to the reply buffer. 01868 // 01869 01870 if (Status == STATUS_SUCCESS) { 01871 01872 if (Msg != NULL) { 01873 01874 LpcpMoveMessage( ReplyMessage, 01875 &Msg->Request, 01876 (&Msg->Request) + 1, 01877 0, 01878 NULL ); 01879 01880 // 01881 // Acquire the LPC mutex and decrement the reference count for the 01882 // message. If the reference count goes to zero the message will be 01883 // deleted. 01884 // 01885 01886 LpcpAcquireLpcpLock(); 01887 01888 if (Msg->RepliedToThread != NULL) { 01889 01890 ObDereferenceObject( Msg->RepliedToThread ); 01891 01892 Msg->RepliedToThread = NULL; 01893 } 01894 01895 LpcpFreeToPortZone( Msg, TRUE ); 01896 01897 LpcpReleaseLpcpLock(); 01898 01899 } else { 01900 01901 Status = STATUS_LPC_REPLY_LOST; 01902 } 01903 01904 } else { 01905 01906 // 01907 // Wait failed, acquire the LPC mutex and free the message. 01908 // 01909 01910 LpcpAcquireLpcpLock(); 01911 01912 if (Msg != NULL) { 01913 01914 LpcpFreeToPortZone( Msg, TRUE ); 01915 } 01916 01917 LpcpReleaseLpcpLock(); 01918 } 01919 01920 // 01921 // And return to our caller 01922 // 01923 01924 return Status; 01925 }


Variable Documentation

ULONG LpcCallBackOperationCount
 

Definition at line 65 of file lpc.h.

ULONG LpcCallOperationCount
 

Definition at line 64 of file lpc.h.

ULONG LpcDatagramOperationCount
 

Definition at line 66 of file lpc.h.


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