test: lpccompl.c File Reference

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 }