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

lpccompl.c File Reference

#include "lpcp.h"

Go to the source code of this file.

Functions

VOID LpcpPrepareToWakeClient (IN PETHREAD ClientThread)
NTSTATUS NtAcceptConnectPort (OUT PHANDLE PortHandle, IN PVOID PortContext OPTIONAL, IN PPORT_MESSAGE ConnectionRequest, IN BOOLEAN AcceptConnection, IN OUT PPORT_VIEW ServerView OPTIONAL, OUT PREMOTE_PORT_VIEW ClientView OPTIONAL)
NTSTATUS NtCompleteConnectPort (IN HANDLE PortHandle)


Function Documentation

VOID LpcpPrepareToWakeClient IN PETHREAD  ClientThread  ) 
 

Definition at line 1001 of file lpccompl.c.

References ClientThread(), and PAGED_CODE.

Referenced by NtAcceptConnectPort(), and NtCompleteConnectPort().

01007 : 01008 01009 This routine is used to prepare the client thread to receive a reply to 01010 its connection request 01011 01012 Arguments: 01013 01014 ClientThread - Specifies the thread we are preparing to wake up 01015 01016 Return Value: 01017 01018 None. 01019 01020 --*/ 01021 01022 { 01023 PAGED_CODE(); 01024 01025 // 01026 // Remove the thread from the rundown list the connection port as we are 01027 // sending a reply. The operation only needs to take place if the 01028 // thread isn't exiting and it's in the lpc reply chain for a connection 01029 // port 01030 // 01031 01032 if ((!ClientThread->LpcExitThreadCalled) && 01033 (!IsListEmpty( &ClientThread->LpcReplyChain ))) { 01034 01035 RemoveEntryList( &ClientThread->LpcReplyChain ); 01036 InitializeListHead( &ClientThread->LpcReplyChain ); 01037 } 01038 01039 // 01040 // And return to our caller 01041 // 01042 01043 return; 01044 } }

NTSTATUS NtAcceptConnectPort OUT PHANDLE  PortHandle,
IN PVOID PortContext  OPTIONAL,
IN PPORT_MESSAGE  ConnectionRequest,
IN BOOLEAN  AcceptConnection,
IN OUT PPORT_VIEW ServerView  OPTIONAL,
OUT PREMOTE_PORT_VIEW ClientView  OPTIONAL
 

Definition at line 40 of file lpccompl.c.

References _LPCP_CONNECTION_MESSAGE::ClientPort, ClientThread(), _LPCP_CONNECTION_MESSAGE::ClientView, _LPCP_PORT_OBJECT::ConnectedPort, _LPCP_PORT_OBJECT::ConnectionPort, _LPCP_PORT_OBJECT::Creator, EXCEPTION_EXECUTE_HANDLER, FALSE, Handle, KeReleaseSemaphore(), KernelMode, KPROCESSOR_MODE, L, LPCP_PORT_OBJECT, LpcpAcquireLpcpLock, LpcPortObjectType, LpcpPrepareToWakeClient(), LpcpPrint, LpcpReleaseLpcpLock, LpcpTrace, _LPCP_PORT_OBJECT::MaxConnectionInfoLength, _LPCP_PORT_OBJECT::MaxMessageLength, MmMapViewOfSection(), MmSectionObjectType, NT_SUCCESS, NtClose(), NTSTATUS(), NULL, ObCreateObject(), ObDereferenceObject, ObInsertObject(), ObReferenceObject, ObReferenceObjectByHandle(), PAGED_CODE, PortHandle, ProbeAndReadStructure, ProbeAndReadUlong, ProbeForRead, ProbeForWrite(), ProbeForWriteHandle, PsGetCurrentProcess, PsGetCurrentThread, PsLookupProcessThreadByCid(), _LPCP_MESSAGE::Request, _LPCP_CONNECTION_MESSAGE::SectionToMap, SERVER_COMMUNICATION_PORT, _LPCP_PORT_OBJECT::ServerProcess, _LPCP_PORT_OBJECT::ServerSectionBase, _LPCP_CONNECTION_MESSAGE::ServerView, Status, and THREAD_TO_PROCESS.

Referenced by RtlpLpcServerCallback(), RtlpLpcWorkerThread(), and ServerHandleConnectionRequest().

00051 : 00052 00053 A server process can accept or reject a client connection request 00054 using the NtAcceptConnectPort service. 00055 00056 The ConnectionRequest parameter must specify a connection request 00057 returned by a previous call to the NtListenPort service. This 00058 service will either complete the connection if the AcceptConnection 00059 parameter is TRUE, or reject the connection request if the 00060 AcceptConnection parameter is FALSE. 00061 00062 In either case, the contents of the data portion of the connection 00063 request is the data to return to the caller of NtConnectPort. 00064 00065 If the connection request is accepted, then two communication port 00066 objects will be created and connected together. One will be 00067 inserted in the client process' handle table and returned to the 00068 client via the PortHandle parameter it specified on the 00069 NtConnectPort service. The other will be inserted in the server 00070 process' handle table and returned via the PortHandle parameter 00071 specified on the NtCompleteConnectPort service. In addition the 00072 two communication ports (client and server) will be linked together. 00073 00074 If the connection request is accepted, and the ServerView parameter 00075 was specified, then the section handle is examined. If it is valid, 00076 then the portion of the section described by the SectionOffset and 00077 ViewSize fields will be mapped into both the client and server 00078 process address spaces. The address in server's address space will 00079 be returned in the ViewBase field. The address in the client's 00080 address space will be returned in the ViewRemoteBase field. The 00081 actual offset and size used to map the section will be returned in 00082 the SectionOffset and ViewSize fields. 00083 00084 Communication port objects are temporary objects that have no names 00085 and cannot be inherited. When either the client or server process 00086 calls the !f NtClose service for a communication port, the port will 00087 be deleted since there can never be more than one outstanding handle 00088 for each communication port. The port object type specific delete 00089 procedure will then be invoked. This delete procedure will examine 00090 the communication port, and if it is connected to another 00091 communication port, it will queue an LPC_PORT_CLOSED datagram to 00092 that port's message queue. This will allow both the client and 00093 server processes to notice when a port becomes disconnected, either 00094 because of an explicit call to NtClose or an implicit call due to 00095 process termination. In addition, the delete procedure will scan 00096 the message queue of the port being closed and for each message 00097 still in the queue, it will return an ERROR_PORT_CLOSED status to 00098 any thread that is waiting for a reply to the message. 00099 00100 Arguments: 00101 00102 PortHandle - A pointer to a variable that will receive the server 00103 communication port object handle value. 00104 00105 PortContext - An uninterpreted pointer that is stored in the 00106 server communication port. This pointer is returned whenever 00107 a message is received for this port. 00108 00109 ConnectionRequest - A pointer to a structure that describes the 00110 connection request being accepted or rejected: 00111 00112 The ConnectionRequest structure 00113 00114 ULONG Length - Specifies the size of this data structure in 00115 bytes. 00116 00117 CLIENT_ID ClientId - Specifies a structure that contains the 00118 client identifier (CLIENT_ID) of the thread that sent the 00119 request. 00120 00121 The ClientId Structure 00122 00123 ULONG UniqueProcessId - A unique value for each process 00124 in the system. 00125 00126 ULONG UniqueThreadId - A unique value for each thread in the 00127 system. 00128 00129 ULONG MessageId - A unique value that identifies the connection 00130 request being completed. 00131 00132 ULONG PortAttributes - This field has no meaning for this service. 00133 00134 ULONG ClientViewSize - This field has no meaning for this service. 00135 00136 AcceptConnection - Specifies a boolean value which indicates where 00137 the connection request is being accepted or rejected. A value 00138 of TRUE means that the connection request is accepted and a 00139 server communication port handle will be created and connected 00140 to the client's communication port handle. A value of FALSE 00141 means that the connection request is not accepted. 00142 00143 ServerView - A pointer to a structure that specifies the section that 00144 the server process will use to send messages back to the client 00145 process connected to this port. 00146 00147 The ServerView Structure 00148 00149 ULONG Length - Specifies the size of this data structure in 00150 bytes. 00151 00152 HANDLE SectionHandle - Specifies an open handle to a section 00153 object. 00154 00155 ULONG SectionOffset - Specifies a field that will receive the 00156 actual offset, in bytes, from the start of the section. The 00157 initial value of this parameter specifies the byte offset 00158 within the section that the client's view is based. The 00159 value is rounded down to the next host page size boundary. 00160 00161 ULONG ViewSize - Specifies the size of the view, in bytes. 00162 00163 PVOID ViewBase - Specifies a field that will receive the base 00164 address of the port memory in the server's address space. 00165 00166 PVOID ViewRemoteBase - Specifies a field that will receive 00167 the base address of the server port's memory in the client's 00168 address space. Used to generate pointers that are 00169 meaningful to the client. 00170 00171 ClientView - An optional pointer to a structure that will receive 00172 information about the client process' view in the server's 00173 address space. The server process can use this information 00174 to validate pointers it receives from the client process. 00175 00176 The ClientView Structure 00177 00178 ULONG Length - Specifies the size of this data structure in 00179 bytes. 00180 00181 PVOID ViewBase - Specifies a field that will receive the base 00182 address of the client port's memory in the server's address 00183 space. 00184 00185 ULONG ViewSize - Specifies a field that will receive the 00186 size, in bytes, of the client's view in the server's address 00187 space. If this field is zero, then client has no view in 00188 the server's address space. 00189 00190 Return Value: 00191 00192 NTSTATUS - An appropriate status value. 00193 00194 --*/ 00195 00196 { 00197 PLPCP_PORT_OBJECT ConnectionPort; 00198 PLPCP_PORT_OBJECT ServerPort; 00199 PLPCP_PORT_OBJECT ClientPort; 00200 PVOID ClientSectionToMap; 00201 HANDLE Handle; 00202 KPROCESSOR_MODE PreviousMode; 00203 NTSTATUS Status; 00204 ULONG ConnectionInfoLength; 00205 PLPCP_MESSAGE Msg; 00206 PLPCP_CONNECTION_MESSAGE ConnectMsg; 00207 PORT_MESSAGE CapturedReplyMessage; 00208 PVOID SectionToMap; 00209 LARGE_INTEGER SectionOffset; 00210 SIZE_T ViewSize; 00211 PEPROCESS ClientProcess; 00212 PETHREAD ClientThread; 00213 PORT_VIEW CapturedServerView; 00214 00215 PAGED_CODE(); 00216 00217 // 00218 // Get previous processor mode and probe output arguments if necessary. 00219 // 00220 00221 PreviousMode = KeGetPreviousMode(); 00222 00223 if (PreviousMode != KernelMode) { 00224 00225 try { 00226 00227 ProbeForWriteHandle( PortHandle ); 00228 00229 ProbeForRead( ConnectionRequest, 00230 sizeof( *ConnectionRequest ), 00231 sizeof( ULONG )); 00232 00233 CapturedReplyMessage = *ConnectionRequest; 00234 00235 if (ARGUMENT_PRESENT( ServerView )) { 00236 00237 CapturedServerView = ProbeAndReadStructure( ServerView, PORT_VIEW ); 00238 00239 if (CapturedServerView.Length != sizeof( *ServerView )) { 00240 00241 return STATUS_INVALID_PARAMETER; 00242 } 00243 00244 ProbeForWrite( ServerView, 00245 sizeof( *ServerView ), 00246 sizeof( ULONG )); 00247 } 00248 00249 if (ARGUMENT_PRESENT( ClientView )) { 00250 00251 if (ProbeAndReadUlong( &ClientView->Length ) != sizeof( *ClientView )) { 00252 00253 return STATUS_INVALID_PARAMETER; 00254 } 00255 00256 ProbeForWrite( ClientView, 00257 sizeof( *ClientView ), 00258 sizeof( ULONG )); 00259 } 00260 00261 } except( EXCEPTION_EXECUTE_HANDLER ) { 00262 00263 return GetExceptionCode(); 00264 } 00265 00266 } else { 00267 00268 // 00269 // Otherwise the previous mode is kernel mode 00270 // 00271 00272 CapturedReplyMessage = *ConnectionRequest; 00273 00274 if (ARGUMENT_PRESENT( ServerView )) { 00275 00276 if (ServerView->Length != sizeof( *ServerView )) { 00277 00278 return STATUS_INVALID_PARAMETER; 00279 } 00280 00281 CapturedServerView = *ServerView; 00282 } 00283 00284 if (ARGUMENT_PRESENT( ClientView )) { 00285 00286 if (ClientView->Length != sizeof( *ClientView )) { 00287 00288 return STATUS_INVALID_PARAMETER; 00289 } 00290 } 00291 } 00292 00293 // 00294 // Translate the ClientId from the connection request into a 00295 // thread pointer. This is a referenced pointer to keep the thread 00296 // from evaporating out from under us. 00297 // 00298 00299 Status = PsLookupProcessThreadByCid( &CapturedReplyMessage.ClientId, 00300 &ClientProcess, 00301 &ClientThread ); 00302 00303 if (!NT_SUCCESS( Status )) { 00304 00305 return Status; 00306 } 00307 00308 // 00309 // Acquire the mutex that guards the LpcReplyMessage field of 00310 // the thread and get the pointer to the message that the thread 00311 // is waiting for a reply to. 00312 // 00313 00314 LpcpAcquireLpcpLock(); 00315 00316 // 00317 // See if the thread is waiting for a reply to the connection request 00318 // specified on this call. If not then a bogus connection request 00319 // has been specified, so release the mutex, dereference the thread 00320 // and return failure. 00321 // 00322 // The check is that the client is waiting for a reply to a connection 00323 // request and that the message id is both valid and lines up correctly 00324 // 00325 00326 if ((ClientThread->LpcReplyMessage == NULL) || 00327 (CapturedReplyMessage.MessageId == 0) || 00328 (ClientThread->LpcReplyMessageId != CapturedReplyMessage.MessageId) || 00329 ((((PLPCP_MESSAGE)ClientThread->LpcReplyMessage)->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) != LPC_CONNECTION_REQUEST)) { 00330 00331 Msg = NULL; 00332 00333 } else { 00334 00335 // 00336 // Remember the LPCP message from the thread 00337 // 00338 00339 Msg = ClientThread->LpcReplyMessage; 00340 00341 // 00342 // Get connection message immediately following the LPCP message 00343 // 00344 00345 ConnectMsg = (PLPCP_CONNECTION_MESSAGE)(Msg + 1); 00346 00347 // 00348 // Remember the client port from the connection message 00349 // 00350 00351 ClientPort = ConnectMsg->ClientPort; 00352 00353 // 00354 // Get a pointer to the connection port from the client port. 00355 // 00356 00357 ConnectionPort = ClientPort->ConnectionPort; 00358 00359 // 00360 // Check if the server process accept the connection 00361 // 00362 00363 if ( ConnectionPort->ServerProcess != PsGetCurrentProcess() ) { 00364 00365 // 00366 // Release the LPC mutex 00367 // 00368 00369 LpcpReleaseLpcpLock(); 00370 00371 ObDereferenceObject( ClientProcess ); 00372 ObDereferenceObject( ClientThread ); 00373 00374 return (STATUS_REPLY_MESSAGE_MISMATCH); 00375 } 00376 00377 // 00378 // Remove the LPC message from the thread 00379 // 00380 00381 ClientThread->LpcReplyMessage = NULL; 00382 00383 // 00384 // Remove the client port from the connection message 00385 // 00386 00387 ConnectMsg->ClientPort = NULL; 00388 00389 // 00390 // Clean up the rest of the client thread. This cleanup use to be 00391 // done unconditionally right before releasing the mutex however 00392 // this causes trouble if our caller supplied a bad reply message 00393 // and we clobber an arbitrary threads state 00394 // 00395 00396 ClientThread->LpcReplyMessageId = 0; 00397 } 00398 00399 // 00400 // Release the mutex that guards the field. 00401 // 00402 00403 LpcpReleaseLpcpLock(); 00404 00405 // 00406 // Now if we did not get an LPCP message from a client thread then this 00407 // isn't a good call and we'll dereference what we thought was the 00408 // client thread/process and tell our caller their mistake 00409 // 00410 00411 if ( !Msg ) { 00412 00413 LpcpPrint(( "%s Attempted AcceptConnectPort to Thread %lx (%s)\n", 00414 PsGetCurrentProcess()->ImageFileName, 00415 ClientThread, 00416 THREAD_TO_PROCESS( ClientThread )->ImageFileName )); 00417 LpcpPrint(( "failed. MessageId == %u\n", CapturedReplyMessage.MessageId )); 00418 LpcpPrint(( " Thread MessageId == %u\n", ClientThread->LpcReplyMessageId )); 00419 LpcpPrint(( " Thread Msg == %x\n", ClientThread->LpcReplyMessage )); 00420 00421 ObDereferenceObject( ClientProcess ); 00422 ObDereferenceObject( ClientThread ); 00423 00424 return (STATUS_REPLY_MESSAGE_MISMATCH); 00425 } 00426 00427 // 00428 // At this point we have a good matching client for this accept connect 00429 // call. 00430 // 00431 00432 LpcpTrace(("Replying to Connect Msg %lx to Port %lx\n", 00433 Msg, ClientPort->ConnectionPort )); 00434 00435 // 00436 // Regardless of whether we are accepting or rejecting the connection, 00437 // return the connection information to the waiting thread. 00438 // 00439 00440 ConnectionInfoLength = CapturedReplyMessage.u1.s1.DataLength; 00441 00442 if (ConnectionInfoLength > ConnectionPort->MaxConnectionInfoLength) { 00443 00444 ConnectionInfoLength = ConnectionPort->MaxConnectionInfoLength; 00445 } 00446 00447 Msg->Request.u1.s1.DataLength = (CSHORT)(sizeof( *ConnectMsg ) + 00448 ConnectionInfoLength); 00449 00450 Msg->Request.u1.s1.TotalLength = (CSHORT)(sizeof( *Msg ) + 00451 Msg->Request.u1.s1.DataLength); 00452 00453 Msg->Request.u2.s2.Type = LPC_REPLY; 00454 Msg->Request.u2.s2.DataInfoOffset = 0; 00455 Msg->Request.ClientId = CapturedReplyMessage.ClientId; 00456 Msg->Request.MessageId = CapturedReplyMessage.MessageId; 00457 Msg->Request.ClientViewSize = 0; 00458 00459 try { 00460 00461 RtlMoveMemory( ConnectMsg + 1, 00462 (PCHAR)(ConnectionRequest + 1), 00463 ConnectionInfoLength ); 00464 00465 } except( EXCEPTION_EXECUTE_HANDLER ) { 00466 00467 Status = GetExceptionCode(); 00468 } 00469 00470 // 00471 // Now it is time to process a positive accept request 00472 // 00473 00474 ClientSectionToMap = NULL; 00475 00476 if (AcceptConnection) { 00477 00478 // 00479 // Allocate and initialize a server communication port object. 00480 // Communication ports have no names, can not be inherited and 00481 // are process private handles. 00482 // 00483 00484 Status = ObCreateObject( PreviousMode, 00485 LpcPortObjectType, 00486 NULL, 00487 PreviousMode, 00488 NULL, 00489 sizeof( LPCP_PORT_OBJECT ), 00490 0, 00491 0, 00492 (PVOID *)&ServerPort ); 00493 00494 if (!NT_SUCCESS( Status )) { 00495 00496 goto bailout; 00497 } 00498 00499 RtlZeroMemory( ServerPort, sizeof( LPCP_PORT_OBJECT )); 00500 00501 ServerPort->Length = sizeof( LPCP_PORT_OBJECT ); 00502 ServerPort->PortContext = PortContext; 00503 ServerPort->Flags = SERVER_COMMUNICATION_PORT; 00504 00505 InitializeListHead( &ServerPort->LpcReplyChainHead ); 00506 InitializeListHead( &ServerPort->LpcDataInfoChainHead ); 00507 00508 // 00509 // Connect the newly created server communication port to the 00510 // connection port with a referenced pointer. Prevents the 00511 // connection port from going away until all of the communication 00512 // ports have been closed. 00513 // 00514 00515 ObReferenceObject( ConnectionPort ); 00516 00517 ServerPort->ConnectionPort = ConnectionPort; 00518 ServerPort->MaxMessageLength = ConnectionPort->MaxMessageLength; 00519 00520 // 00521 // Connect the client and server communication ports together 00522 // with unreferenced pointers. They are unreferenced so that 00523 // the PortObjectType delete procedure will get called when a 00524 // communication port is closed. If this were not the case then 00525 // we would need a special NtClosePort system service in order 00526 // to tear down a pair of connected communication ports. 00527 // 00528 00529 ServerPort->ConnectedPort = ClientPort; 00530 ClientPort->ConnectedPort = ServerPort; 00531 00532 ServerPort->Creator = PsGetCurrentThread()->Cid; 00533 ClientPort->Creator = Msg->Request.ClientId; 00534 00535 // 00536 // If the client has allocated a port memory section that is mapped 00537 // into the client's address space, then map a view of the same 00538 // section for the server process to see. 00539 // 00540 00541 LpcpAcquireLpcpLock(); 00542 00543 ClientSectionToMap = ConnectMsg->SectionToMap; 00544 ConnectMsg->SectionToMap = NULL; 00545 00546 LpcpReleaseLpcpLock(); 00547 00548 if (ClientSectionToMap) { 00549 00550 LARGE_INTEGER LargeSectionOffset; 00551 00552 LargeSectionOffset.LowPart = ConnectMsg->ClientView.SectionOffset; 00553 LargeSectionOffset.HighPart = 0; 00554 00555 Status = MmMapViewOfSection( ClientSectionToMap, 00556 PsGetCurrentProcess(), 00557 &ServerPort->ClientSectionBase, 00558 0, 00559 0, 00560 &LargeSectionOffset, 00561 &ConnectMsg->ClientView.ViewSize, 00562 ViewUnmap, 00563 0, 00564 PAGE_READWRITE ); 00565 00566 ConnectMsg->ClientView.SectionOffset = LargeSectionOffset.LowPart; 00567 00568 if (NT_SUCCESS( Status )) { 00569 00570 ConnectMsg->ClientView.ViewRemoteBase = ServerPort->ClientSectionBase; 00571 00572 } else { 00573 00574 // 00575 // At this point we're really going to drop all the way 00576 // out to the label bailout: because everything else is 00577 // protected with a test against Status. But first we have 00578 // to release the server port that we've just created 00579 // 00580 00581 ObDereferenceObject( ServerPort ); 00582 } 00583 } 00584 00585 // 00586 // If the server process has allocated a port memory section for 00587 // send data to the client on call back requests, map two views 00588 // of that section, the first for the server process and the 00589 // second view for the client process. Return the location of the 00590 // server's view to the caller of this function. Return the 00591 // client's view to the client process via the reply to the 00592 // connection request. 00593 // 00594 00595 if (NT_SUCCESS( Status ) && ARGUMENT_PRESENT( ServerView )) { 00596 00597 LARGE_INTEGER LargeSectionOffset; 00598 00599 LargeSectionOffset.LowPart = CapturedServerView.SectionOffset; 00600 LargeSectionOffset.HighPart = 0; 00601 00602 // 00603 // Map in the section into the servers address space 00604 // 00605 00606 // 00607 // **** Does this call need to verify that the section handle 00608 // is still valid. 00609 // 00610 00611 Status = ObReferenceObjectByHandle( CapturedServerView.SectionHandle, 00612 SECTION_MAP_READ | 00613 SECTION_MAP_WRITE, 00614 MmSectionObjectType, 00615 PreviousMode, 00616 (PVOID *)&SectionToMap, 00617 NULL ); 00618 00619 if (NT_SUCCESS( Status )) { 00620 00621 Status = MmMapViewOfSection( SectionToMap, 00622 PsGetCurrentProcess(), 00623 &ServerPort->ServerSectionBase, 00624 0, 00625 0, 00626 &LargeSectionOffset, 00627 &CapturedServerView.ViewSize, 00628 ViewUnmap, 00629 0, 00630 PAGE_READWRITE ); 00631 00632 if (NT_SUCCESS( Status )) { 00633 00634 CapturedServerView.SectionOffset = LargeSectionOffset.LowPart; 00635 00636 CapturedServerView.ViewBase = ServerPort->ServerSectionBase; 00637 00638 00639 SectionOffset.LowPart = CapturedServerView.SectionOffset; 00640 SectionOffset.HighPart = 0; 00641 00642 ViewSize = CapturedServerView.ViewSize; 00643 00644 Status = MmMapViewOfSection( SectionToMap, 00645 ClientProcess, 00646 &ClientPort->ServerSectionBase, 00647 0, 00648 0, 00649 &SectionOffset, 00650 &ViewSize, 00651 ViewUnmap, 00652 0, 00653 PAGE_READWRITE ); 00654 00655 if (NT_SUCCESS( Status )) { 00656 00657 // 00658 // Let the server know where the client's view of the 00659 // section got mapped 00660 // 00661 00662 CapturedServerView.ViewRemoteBase = ClientPort->ServerSectionBase; 00663 00664 // 00665 // Let the client know where the server's view of the 00666 // section got mapped 00667 // 00668 00669 ConnectMsg->ServerView.ViewBase = ClientPort->ServerSectionBase; 00670 ConnectMsg->ServerView.ViewSize = ViewSize; 00671 00672 } else { 00673 00674 ObDereferenceObject( ServerPort ); 00675 } 00676 00677 } else { 00678 00679 ObDereferenceObject( ServerPort ); 00680 } 00681 00682 ObDereferenceObject( SectionToMap ); 00683 00684 } else { 00685 00686 ObDereferenceObject( ServerPort ); 00687 } 00688 } 00689 00690 // 00691 // Insert the server communication port object in specified object 00692 // table. Set port handle value if successful. If not 00693 // successful, then the port will have been dereferenced, which 00694 // will cause it to be freed, after our delete procedure is 00695 // called. The delete procedure will undo the work done to 00696 // initialize the port. 00697 // 00698 00699 if (NT_SUCCESS( Status )) { 00700 00701 // 00702 // Add an extra reference to the object otherwise right when we 00703 // create the handle a rouge caller might close and destroy the 00704 // port. 00705 // 00706 00707 ObReferenceObject( ServerPort ); 00708 00709 // 00710 // Now add the handle 00711 // 00712 00713 Status = ObInsertObject( ServerPort, 00714 NULL, 00715 PORT_ALL_ACCESS, 00716 0, 00717 (PVOID *)NULL, 00718 &Handle ); 00719 00720 if (NT_SUCCESS( Status )) { 00721 00722 try { 00723 00724 if (ARGUMENT_PRESENT( ServerView )) { 00725 00726 *ServerView = CapturedServerView; 00727 } 00728 00729 if (ARGUMENT_PRESENT( ClientView )) { 00730 00731 ClientView->ViewBase = ConnectMsg->ClientView.ViewRemoteBase; 00732 ClientView->ViewSize = ConnectMsg->ClientView.ViewSize; 00733 } 00734 00735 *PortHandle = Handle; 00736 00737 if (!ARGUMENT_PRESENT( PortContext )) { 00738 00739 ServerPort->PortContext = Handle; 00740 } 00741 00742 ServerPort->ClientThread = ClientThread; 00743 00744 LpcpAcquireLpcpLock(); 00745 ClientThread->LpcReplyMessage = Msg; 00746 LpcpReleaseLpcpLock(); 00747 00748 ClientThread = NULL; 00749 00750 } except( EXCEPTION_EXECUTE_HANDLER ) { 00751 00752 NtClose( Handle ); 00753 Status = GetExceptionCode(); 00754 } 00755 } 00756 00757 // 00758 // Now we can remove the extra object reference 00759 // 00760 00761 ObDereferenceObject( ServerPort ); 00762 } 00763 00764 } else { 00765 00766 // 00767 // Otherwise the server has not accepted the connection request 00768 // 00769 00770 LpcpPrint(( "Refusing connection from %x.%x\n", 00771 Msg->Request.ClientId.UniqueProcess, 00772 Msg->Request.ClientId.UniqueThread )); 00773 } 00774 00775 bailout: 00776 00777 if ( ClientSectionToMap ) { 00778 00779 ObDereferenceObject( ClientSectionToMap ); 00780 } 00781 00782 // 00783 // If the client is not null then this is an error condition and we need 00784 // to cleanup and wake the client thread. In success cases the client 00785 // thread is woken up with a call to Complete Connect Request 00786 // 00787 00788 if (ClientThread != NULL) { 00789 00790 LpcpAcquireLpcpLock(); 00791 00792 ClientThread->LpcReplyMessage = Msg; 00793 00794 if (AcceptConnection) { 00795 00796 LpcpPrint(( "LPC: Failing AcceptConnection with Status == %x\n", Status )); 00797 } 00798 00799 LpcpPrepareToWakeClient( ClientThread ); 00800 00801 LpcpReleaseLpcpLock(); 00802 00803 // 00804 // Wake up the thread that is waiting for an answer to its connection 00805 // request inside of NtConnectPort. 00806 // 00807 00808 KeReleaseSemaphore( &ClientThread->LpcReplySemaphore, 00809 0, 00810 1L, 00811 FALSE ); 00812 00813 // 00814 // Dereference client thread and return the system service status. 00815 // 00816 00817 ObDereferenceObject( ClientThread ); 00818 } 00819 00820 if (ClientPort) { 00821 00822 ObDereferenceObject( ClientPort ); 00823 } 00824 00825 ObDereferenceObject( ClientProcess ); 00826 00827 // 00828 // And return to our caller 00829 // 00830 00831 return Status; 00832 }

NTSTATUS NtCompleteConnectPort IN HANDLE  PortHandle  ) 
 

Definition at line 836 of file lpccompl.c.

References _LPCP_PORT_OBJECT::ClientThread, ClientThread(), _LPCP_PORT_OBJECT::ConnectionPort, FALSE, _LPCP_PORT_OBJECT::Flags, KeReleaseSemaphore(), KPROCESSOR_MODE, L, LpcpAcquireLpcpLock, LpcpPrepareToWakeClient(), LpcpReferencePortObject, LpcpReleaseLpcpLock, _LPCP_PORT_OBJECT::LpcReplyChainHead, NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, PAGED_CODE, PORT_TYPE, PortHandle, SERVER_COMMUNICATION_PORT, and Status.

Referenced by RtlpLpcWorkerThread(), and ServerHandleConnectionRequest().

00842 : 00843 00844 This routine is called by the server after it calls NtAcceptConnectPort to 00845 wake up the client thread. Between calling NtAcceptConnectPort and 00846 NtCompleteConnectPort the server can do whatever work is necessary before 00847 waking up the client 00848 00849 Arguments: 00850 00851 PortHandle - Supplies a handle to the server communcation port 00852 00853 Return Value: 00854 00855 NTSTATUS - An appropriate status value. 00856 00857 --*/ 00858 00859 { 00860 PLPCP_PORT_OBJECT PortObject; 00861 KPROCESSOR_MODE PreviousMode; 00862 NTSTATUS Status; 00863 PETHREAD ClientThread; 00864 00865 PAGED_CODE(); 00866 00867 // 00868 // Get previous processor mode 00869 // 00870 00871 PreviousMode = KeGetPreviousMode(); 00872 00873 // 00874 // Reference the port object by handle 00875 // 00876 00877 Status = LpcpReferencePortObject( PortHandle, 00878 0, 00879 PreviousMode, 00880 &PortObject ); 00881 00882 if (!NT_SUCCESS( Status )) { 00883 00884 return Status; 00885 } 00886 00887 // 00888 // Error if a port type is invalid. 00889 // 00890 00891 if ((PortObject->Flags & PORT_TYPE) != SERVER_COMMUNICATION_PORT) { 00892 00893 ObDereferenceObject( PortObject ); 00894 00895 return STATUS_INVALID_PORT_HANDLE; 00896 } 00897 00898 // 00899 // Under the LPC lock we need to check for a client thread and if there 00900 // is one we'll remember and remove the client thread, and then prepare 00901 // to wake the client 00902 // 00903 00904 LpcpAcquireLpcpLock(); 00905 00906 if (PortObject->ClientThread == NULL) { 00907 00908 LpcpReleaseLpcpLock(); 00909 00910 ObDereferenceObject( PortObject ); 00911 00912 return STATUS_INVALID_PARAMETER; 00913 } 00914 00915 ClientThread = PortObject->ClientThread; 00916 00917 // 00918 // Double check that the thread is still waiting for a reply message 00919 // 00920 00921 if (ClientThread->LpcReplyMessage == NULL) { 00922 00923 LpcpReleaseLpcpLock(); 00924 00925 ObDereferenceObject( PortObject ); 00926 00927 return STATUS_PORT_DISCONNECTED; 00928 } 00929 00930 // 00931 // The check needs to ensure that the client thread is really on the 00932 // reply chain for the sever's connection port. This is a quick and 00933 // dirty fix for NT 5.0. We zoom down the connection port lpc reply 00934 // chain looking for an entry that contains the client threads. If 00935 // we find a match it's okay if we don't it's bad. 00936 // 00937 00938 { 00939 PLIST_ENTRY Entry; 00940 00941 for (Entry = PortObject->ConnectionPort->LpcReplyChainHead.Flink; 00942 Entry != (PLIST_ENTRY)(&PortObject->ConnectionPort->LpcReplyChainHead.Flink); 00943 Entry = Entry->Flink) { 00944 00945 if (Entry == ((PLIST_ENTRY)(&ClientThread->LpcReplyChain.Flink))) { 00946 00947 break; 00948 } 00949 } 00950 00951 if (Entry != ((PLIST_ENTRY)(&ClientThread->LpcReplyChain.Flink))) { 00952 00953 LpcpReleaseLpcpLock(); 00954 00955 ObDereferenceObject( PortObject ); 00956 00957 return STATUS_PORT_DISCONNECTED; 00958 } 00959 } 00960 00961 // 00962 // Now do the wakeup 00963 // 00964 00965 PortObject->ClientThread = NULL; 00966 00967 LpcpPrepareToWakeClient( ClientThread ); 00968 00969 LpcpReleaseLpcpLock(); 00970 00971 // 00972 // Wake up the thread that is waiting for an answer to its connection 00973 // request inside of NtConnectPort. 00974 // 00975 00976 KeReleaseSemaphore( &ClientThread->LpcReplySemaphore, 00977 0, 00978 1L, 00979 FALSE ); 00980 00981 // 00982 // Dereference client thread 00983 // 00984 00985 ObDereferenceObject( ClientThread ); 00986 ObDereferenceObject( PortObject ); 00987 00988 // 00989 // And return to our caller 00990 // 00991 00992 return Status; 00993 }


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