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

lpcsvr.c File Reference

#include <ntos.h>
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include "lpcsvr.h"

Go to the source code of this file.

Defines

#define RtlpLpcLockServer(s)   RtlEnterCriticalSection( &s->Lock );
#define RtlpLpcUnlockServer(s)   RtlLeaveCriticalSection( &s->Lock );
#define RtlpLpcContextFromClient(p)   ( CONTAINING_RECORD( p, LPCSVR_CONTEXT, PrivateContext ) )

Functions

VOID RtlpLpcDerefContext (PLPCSVR_CONTEXT Context, PLPCSVR_MESSAGE Message)
VOID RtlpLpcWorkerThread (PVOID Parameter)
VOID RtlpLpcServerCallback (PVOID Parameter, BOOLEAN TimedOut)
NTSTATUS RtlCreateLpcServer (POBJECT_ATTRIBUTES PortName, PLPCSVR_INITIALIZE Init, PLARGE_INTEGER IdleTimeout, ULONG MessageSize, ULONG Options, PVOID *LpcServer)
NTSTATUS RtlShutdownLpcServer (PVOID LpcServer)
NTSTATUS RtlImpersonateLpcClient (PVOID Context, PPORT_MESSAGE Message)
NTSTATUS RtlCallbackLpcClient (PVOID Context, PPORT_MESSAGE Request, PPORT_MESSAGE Callback)


Define Documentation

#define RtlpLpcContextFromClient  )     ( CONTAINING_RECORD( p, LPCSVR_CONTEXT, PrivateContext ) )
 

Definition at line 27 of file lpcsvr.c.

Referenced by RtlCallbackLpcClient(), and RtlImpersonateLpcClient().

#define RtlpLpcLockServer  )     RtlEnterCriticalSection( &s->Lock );
 

Definition at line 24 of file lpcsvr.c.

Referenced by RtlpLpcDerefContext(), RtlpLpcServerCallback(), and RtlShutdownLpcServer().

#define RtlpLpcUnlockServer  )     RtlLeaveCriticalSection( &s->Lock );
 

Definition at line 25 of file lpcsvr.c.

Referenced by RtlpLpcDerefContext(), RtlpLpcServerCallback(), and RtlShutdownLpcServer().


Function Documentation

NTSTATUS RtlCallbackLpcClient PVOID  Context,
PPORT_MESSAGE  Request,
PPORT_MESSAGE  Callback
 

Definition at line 712 of file lpcsvr.c.

References _LPCSVR_CONTEXT::CommPort, NtRequestWaitReplyPort(), NTSTATUS(), Request(), RtlpLpcContextFromClient, and Status.

00717 { 00718 NTSTATUS Status ; 00719 PLPCSVR_CONTEXT LpcContext ; 00720 00721 if ( Request != Callback ) 00722 { 00723 Callback->ClientId = Request->ClientId ; 00724 Callback->MessageId = Request->MessageId ; 00725 } 00726 00727 LpcContext = RtlpLpcContextFromClient( Context ); 00728 00729 Status = NtRequestWaitReplyPort( 00730 LpcContext->CommPort, 00731 Callback, 00732 Callback 00733 ); 00734 00735 return Status ; 00736 00737 }

NTSTATUS RtlCreateLpcServer POBJECT_ATTRIBUTES  PortName,
PLPCSVR_INITIALIZE  Init,
PLARGE_INTEGER  IdleTimeout,
ULONG  MessageSize,
ULONG  Options,
PVOID *  LpcServer
 

Definition at line 463 of file lpcsvr.c.

References LPCSVR_MESSAGE, LPCSVR_SERVER, NT_SUCCESS, NtCreateWaitablePort(), NTSTATUS(), NULL, PortName, RtlAllocateHeap, RtlDeleteCriticalSection(), RtlFreeHeap, RtlInitializeCriticalSectionAndSpinCount(), RtlpLpcServerCallback(), RtlRegisterWait(), Server, and Status.

00471 { 00472 PLPCSVR_SERVER Server ; 00473 NTSTATUS Status ; 00474 HANDLE Thread ; 00475 CLIENT_ID Id ; 00476 00477 *LpcServer = NULL ; 00478 00479 Server = RtlAllocateHeap( RtlProcessHeap(), 00480 0, 00481 sizeof( LPCSVR_SERVER ) ); 00482 00483 if ( !Server ) 00484 { 00485 return STATUS_INSUFFICIENT_RESOURCES ; 00486 } 00487 00488 RtlInitializeCriticalSectionAndSpinCount( 00489 &Server->Lock, 00490 1000 ); 00491 00492 InitializeListHead( &Server->ContextList ); 00493 Server->ContextCount = 0 ; 00494 00495 Server->Init = *Init ; 00496 if ( !IdleTimeout ) 00497 { 00498 Server->Timeout.QuadPart = 0 ; 00499 } 00500 else 00501 { 00502 Server->Timeout = *IdleTimeout ; 00503 } 00504 00505 Server->MessageSize = MessageSize + sizeof( LPCSVR_MESSAGE ) - 00506 sizeof( PORT_MESSAGE ); 00507 00508 Server->MessagePool = 0 ; 00509 Server->MessagePoolSize = 0 ; 00510 Server->MessagePoolLimit = 4 ; 00511 00512 Server->Flags = Options ; 00513 00514 // 00515 // Create the LPC port: 00516 // 00517 00518 Status = NtCreateWaitablePort( 00519 &Server->Port, 00520 PortName, 00521 MessageSize, 00522 MessageSize, 00523 MessageSize * 4 00524 ); 00525 00526 if ( !NT_SUCCESS( Status ) ) 00527 { 00528 RtlDeleteCriticalSection( &Server->Lock ); 00529 RtlFreeHeap( RtlProcessHeap(), 0, Server ); 00530 return Status ; 00531 } 00532 00533 *LpcServer = Server ; 00534 00535 // 00536 // Now, post the handle over to a wait queue 00537 // 00538 Status = RtlRegisterWait( 00539 &Server->WaitHandle, 00540 Server->Port, 00541 RtlpLpcServerCallback, 00542 Server, 00543 0xFFFFFFFF, 00544 WT_EXECUTEONLYONCE 00545 ); 00546 00547 return Status ; 00548 }

NTSTATUS RtlImpersonateLpcClient PVOID  Context,
PPORT_MESSAGE  Message
 

Definition at line 696 of file lpcsvr.c.

References _LPCSVR_CONTEXT::CommPort, NtImpersonateClientOfPort(), and RtlpLpcContextFromClient.

00700 { 00701 PLPCSVR_CONTEXT LpcContext ; 00702 00703 LpcContext = RtlpLpcContextFromClient( Context ); 00704 00705 return NtImpersonateClientOfPort( 00706 LpcContext->CommPort, 00707 Message ); 00708 00709 }

VOID RtlpLpcDerefContext PLPCSVR_CONTEXT  Context,
PLPCSVR_MESSAGE  Message
 

Definition at line 46 of file lpcsvr.c.

References _LPCSVR_CONTEXT::CommPort, _LPCSVR_MESSAGE::Header, _LPCSVR_CONTEXT::List, NtClose(), PLPCSVR_CONTEXT, PLPCSVR_MESSAGE, PLPCSVR_SERVER, _LPCSVR_CONTEXT::RefCount, RtlFreeHeap, RtlpLpcLockServer, RtlpLpcUnlockServer, _LPCSVR_CONTEXT::Server, and Server.

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

00050 { 00051 PLPCSVR_SERVER Server ; 00052 00053 Server = Context->Server ; 00054 00055 if ( InterlockedDecrement( &Context->RefCount ) < 0 ) 00056 { 00057 // 00058 // All gone, time to clean up: 00059 // 00060 00061 RtlpLpcLockServer( Server ); 00062 00063 if ( Context->List.Flink ) 00064 { 00065 RemoveEntryList( &Context->List ); 00066 00067 Server->ContextCount -- ; 00068 00069 } 00070 else 00071 { 00072 if ( Message ) 00073 { 00074 RtlFreeHeap( RtlProcessHeap(), 00075 0, 00076 Message ); 00077 } 00078 } 00079 00080 RtlpLpcUnlockServer( Server ); 00081 00082 if ( Context->CommPort ) 00083 { 00084 NtClose( Context->CommPort ); 00085 } 00086 00087 RtlFreeHeap( RtlProcessHeap(), 00088 0, 00089 Context ); 00090 } 00091 else 00092 { 00093 RtlpLpcLockServer( Server ); 00094 00095 Server->MessagePoolSize++ ; 00096 00097 if ( Server->MessagePoolSize < Server->MessagePoolLimit ) 00098 { 00099 Message->Header.Next = Server->MessagePool ; 00100 00101 Server->MessagePool = Message ; 00102 } 00103 else 00104 { 00105 Server->MessagePoolSize-- ; 00106 00107 RtlFreeHeap( RtlProcessHeap(), 00108 0, 00109 Message ); 00110 00111 } 00112 00113 RtlpLpcUnlockServer( Server ); 00114 } 00115 00116 }

VOID RtlpLpcServerCallback PVOID  Parameter,
BOOLEAN  TimedOut
 

Definition at line 260 of file lpcsvr.c.

References _LPCSVR_CONTEXT::CommPort, DbgPrint, FALSE, _LPCSVR_MESSAGE::Header, _LPCSVR_CONTEXT::List, LPCSVR_CONTEXT, LPCSVR_SHUTDOWN_PENDING, LPCSVR_SYNCHRONOUS, _LPCSVR_MESSAGE::Message, NT_SUCCESS, NtAcceptConnectPort(), NtDelayExecution(), NtReplyWaitReceivePortEx(), NTSTATUS(), NULL, _LPCSVR_CONTEXT::RefCount, RtlAllocateHeap, RtlpLpcDerefContext(), RtlpLpcLockServer, RtlpLpcServerCallback(), RtlpLpcUnlockServer, RtlpLpcWorkerThread(), RtlQueueWorkItem(), RtlRegisterWait(), _LPCSVR_CONTEXT::Server, Server, and Status.

Referenced by RtlCreateLpcServer(), and RtlpLpcServerCallback().

00264 { 00265 PLPCSVR_SERVER Server ; 00266 NTSTATUS Status ; 00267 PLPCSVR_MESSAGE Message ; 00268 PLPCSVR_CONTEXT Context ; 00269 PLARGE_INTEGER RealTimeout ; 00270 LPCSVR_FILTER_RESULT FilterResult ; 00271 00272 Server = (PLPCSVR_SERVER) Parameter ; 00273 00274 if ( Server->WaitHandle ) 00275 { 00276 Server->WaitHandle = NULL ; 00277 } 00278 00279 while ( 1 ) 00280 { 00281 DbgPrint("Entering LPC server\n" ); 00282 00283 RtlpLpcLockServer( Server ); 00284 00285 if ( Server->Flags & LPCSVR_SHUTDOWN_PENDING ) 00286 { 00287 break; 00288 } 00289 00290 if ( Server->MessagePool ) 00291 { 00292 Message = Server->MessagePool ; 00293 Server->MessagePool = Message->Header.Next ; 00294 } 00295 else 00296 { 00297 Message = RtlAllocateHeap( RtlProcessHeap(), 00298 0, 00299 Server->MessageSize ); 00300 00301 } 00302 00303 RtlpLpcUnlockServer( Server ); 00304 00305 if ( !Message ) 00306 { 00307 LARGE_INTEGER SleepInterval ; 00308 00309 SleepInterval.QuadPart = 125 * 10000 ; 00310 00311 NtDelayExecution( FALSE, &SleepInterval ); 00312 continue; 00313 } 00314 00315 00316 if ( Server->Timeout.QuadPart ) 00317 { 00318 RealTimeout = &Server->Timeout ; 00319 } 00320 else 00321 { 00322 RealTimeout = NULL ; 00323 } 00324 00325 Status = NtReplyWaitReceivePortEx( 00326 Server->Port, 00327 &Context, 00328 NULL, 00329 &Message->Message, 00330 RealTimeout ); 00331 00332 DbgPrint("Server: NtReplyWaitReceivePort completed with %x\n", Status ); 00333 00334 if ( NT_SUCCESS( Status ) ) 00335 { 00336 // 00337 // If we timed out, nobody was waiting for us: 00338 // 00339 00340 if ( Status == STATUS_TIMEOUT ) 00341 { 00342 // 00343 // Set up a general wait that will call back to this function 00344 // when ready. 00345 // 00346 00347 RtlpLpcLockServer( Server ); 00348 00349 if ( ( Server->Flags & LPCSVR_SHUTDOWN_PENDING ) == 0 ) 00350 { 00351 00352 Status = RtlRegisterWait( &Server->WaitHandle, 00353 Server->Port, 00354 RtlpLpcServerCallback, 00355 Server, 00356 0xFFFFFFFF, 00357 WT_EXECUTEONLYONCE ); 00358 } 00359 00360 RtlpLpcUnlockServer( Server ); 00361 00362 break; 00363 00364 } 00365 00366 if ( Status == STATUS_SUCCESS ) 00367 { 00368 if ( Context ) 00369 { 00370 InterlockedIncrement( &Context->RefCount ); 00371 } 00372 else 00373 { 00374 // 00375 // New connection. Create a new context record 00376 // 00377 00378 Context = RtlAllocateHeap( RtlProcessHeap(), 00379 0, 00380 sizeof( LPCSVR_CONTEXT ) + 00381 Server->Init.ContextSize ); 00382 00383 if ( !Context ) 00384 { 00385 HANDLE Bogus ; 00386 00387 Status = NtAcceptConnectPort( 00388 &Bogus, 00389 NULL, 00390 &Message->Message, 00391 FALSE, 00392 NULL, 00393 NULL ); 00394 00395 RtlpLpcLockServer( Server ); 00396 00397 Message->Header.Next = Server->MessagePool ; 00398 Server->MessagePool = Message ; 00399 00400 RtlpLpcUnlockServer( Server ); 00401 00402 continue; 00403 } 00404 00405 Context->Server = Server ; 00406 Context->RefCount = 1 ; 00407 Context->CommPort = NULL ; 00408 00409 RtlpLpcLockServer( Server ); 00410 00411 InsertTailList( &Server->ContextList, &Context->List ); 00412 Server->ContextCount++ ; 00413 00414 RtlpLpcUnlockServer( Server ); 00415 } 00416 00417 00418 Message->Header.Context = Context ; 00419 00420 FilterResult = LpcFilterAsync ; 00421 00422 if ( Server->Init.FilterFn ) 00423 { 00424 FilterResult = Server->Init.FilterFn( Context, &Message->Message ); 00425 00426 if (FilterResult == LpcFilterDrop ) 00427 { 00428 RtlpLpcDerefContext( Context, Message ); 00429 00430 continue; 00431 00432 } 00433 } 00434 00435 if ( (Server->Flags & LPCSVR_SYNCHRONOUS) || 00436 (FilterResult == LpcFilterSync) ) 00437 { 00438 RtlpLpcWorkerThread( Message ); 00439 } 00440 else 00441 { 00442 RtlQueueWorkItem( RtlpLpcWorkerThread, 00443 Message, 00444 0 ); 00445 00446 } 00447 } 00448 } 00449 else 00450 { 00451 // 00452 // Error? Better shut down... 00453 // 00454 00455 break; 00456 } 00457 00458 } 00459 00460 }

VOID RtlpLpcWorkerThread PVOID  Parameter  ) 
 

Definition at line 134 of file lpcsvr.c.

References _LPCSVR_CONTEXT::CommPort, DbgPrint, FALSE, _LPCSVR_MESSAGE::Header, _LPCSVR_SERVER::Init, _LPCSVR_MESSAGE::Message, NT_SUCCESS, NtAcceptConnectPort(), NtCompleteConnectPort(), NtReplyPort(), NTSTATUS(), NULL, _LPCSVR_CONTEXT::PrivateContext, _LPCSVR_CONTEXT::RefCount, RtlpLpcDerefContext(), _LPCSVR_CONTEXT::Server, and Status.

Referenced by RtlpLpcServerCallback().

00137 { 00138 PLPCSVR_MESSAGE Message ; 00139 PLPCSVR_CONTEXT Context ; 00140 NTSTATUS Status ; 00141 BOOLEAN Accept ; 00142 00143 Message = (PLPCSVR_MESSAGE) Parameter ; 00144 00145 Context = Message->Header.Context ; 00146 00147 switch ( Message->Message.u2.s2.Type & 0xF ) 00148 { 00149 case LPC_REQUEST: 00150 case LPC_DATAGRAM: 00151 DbgPrint("Calling Server's Request function\n"); 00152 Status = Context->Server->Init.RequestFn( 00153 &Context->PrivateContext, 00154 &Message->Message, 00155 &Message->Message 00156 ); 00157 00158 if ( NT_SUCCESS( Status ) ) 00159 { 00160 Status = NtReplyPort( Context->CommPort, 00161 &Message->Message ); 00162 00163 if ( !NT_SUCCESS( Status ) ) 00164 { 00165 // 00166 // See what happened. The client may have gone away already. 00167 // 00168 00169 break; 00170 00171 } 00172 } 00173 break; 00174 00175 case LPC_CONNECTION_REQUEST: 00176 DbgPrint("Calling Server's Connect function\n"); 00177 Status = Context->Server->Init.ConnectFn( 00178 &Context->PrivateContext, 00179 &Message->Message, 00180 &Accept 00181 ); 00182 00183 // 00184 // If the comm port is still null, then do the accept. Otherwise, the 00185 // server called RtlAcceptConnectPort() explicitly, to set up a view. 00186 // 00187 00188 if ( NT_SUCCESS( Status ) ) 00189 { 00190 if ( Context->CommPort == NULL ) 00191 { 00192 Status = NtAcceptConnectPort( 00193 &Context->CommPort, 00194 Context, 00195 &Message->Message, 00196 Accept, 00197 NULL, 00198 NULL ); 00199 00200 if ( !Accept ) 00201 { 00202 // 00203 // Yank the context out of the list, since it is worthless 00204 // 00205 00206 Context->RefCount = 0 ; 00207 00208 } 00209 else 00210 { 00211 Status = NtCompleteConnectPort( Context->CommPort ); 00212 } 00213 } 00214 00215 } 00216 else 00217 { 00218 Status = NtAcceptConnectPort( 00219 &Context->CommPort, 00220 NULL, 00221 &Message->Message, 00222 FALSE, 00223 NULL, 00224 NULL ); 00225 00226 Context->RefCount = 0 ; 00227 00228 } 00229 00230 break; 00231 00232 case LPC_CLIENT_DIED: 00233 DbgPrint( "Calling Server's Rundown function\n" ); 00234 Status = Context->Server->Init.RundownFn( 00235 &Context->PrivateContext, 00236 &Message->Message 00237 ); 00238 00239 InterlockedDecrement( &Context->RefCount ); 00240 00241 break; 00242 00243 default: 00244 // 00245 // An unexpected message came through. Normal LPC servers 00246 // don't handle the other types of messages. Drop it. 00247 // 00248 00249 break; 00250 } 00251 00252 RtlpLpcDerefContext( Context, Message ); 00253 00254 return ; 00255 00256 00257 }

NTSTATUS RtlShutdownLpcServer PVOID  LpcServer  ) 
 

Definition at line 552 of file lpcsvr.c.

References FALSE, _LPCSVR_CONTEXT::List, List, LPCSVR_SHUTDOWN_PENDING, NT_SUCCESS, NtClose(), NtCreateEvent(), NTSTATUS(), NtWaitForSingleObject(), NULL, _LPCSVR_CONTEXT::PrivateContext, RtlDeregisterWait(), RtlFreeHeap, RtlpLpcDerefContext(), RtlpLpcLockServer, RtlpLpcUnlockServer, Server, and Status.

00555 { 00556 PLPCSVR_SERVER Server ; 00557 OBJECT_ATTRIBUTES ObjA ; 00558 PLIST_ENTRY Scan ; 00559 PLPCSVR_CONTEXT Context ; 00560 PLPCSVR_MESSAGE Message ; 00561 NTSTATUS Status ; 00562 00563 Server = (PLPCSVR_SERVER) LpcServer ; 00564 00565 RtlpLpcLockServer( Server ); 00566 00567 if ( Server->Flags & LPCSVR_SHUTDOWN_PENDING ) 00568 { 00569 RtlpLpcUnlockServer( Server ); 00570 00571 return STATUS_PENDING ; 00572 } 00573 00574 if ( Server->WaitHandle ) 00575 { 00576 RtlDeregisterWait( Server->WaitHandle ); 00577 00578 Server->WaitHandle = NULL ; 00579 } 00580 00581 if ( Server->Timeout.QuadPart == 0 ) 00582 { 00583 RtlpLpcUnlockServer( Server ); 00584 00585 return STATUS_NOT_IMPLEMENTED ; 00586 } 00587 00588 // 00589 // If there are receives still pending, we have to sync 00590 // with those threads. To do so, we will tag the shutdown 00591 // flag, and then wait the timeout amount. 00592 // 00593 00594 if ( Server->ReceiveThreads != 0 ) 00595 { 00596 00597 InitializeObjectAttributes( &ObjA, 00598 NULL, 00599 0, 00600 0, 00601 0 ); 00602 00603 Status = NtCreateEvent( &Server->ShutdownEvent, 00604 EVENT_ALL_ACCESS, 00605 &ObjA, 00606 NotificationEvent, 00607 FALSE ); 00608 00609 if ( !NT_SUCCESS( Status ) ) 00610 { 00611 RtlpLpcUnlockServer( Server ); 00612 00613 return Status ; 00614 00615 } 00616 00617 Server->Flags |= LPCSVR_SHUTDOWN_PENDING ; 00618 00619 RtlpLpcUnlockServer( Server ); 00620 00621 Status = NtWaitForSingleObject( 00622 Server->ShutdownEvent, 00623 FALSE, 00624 &Server->Timeout ); 00625 00626 if ( Status == STATUS_TIMEOUT ) 00627 { 00628 // 00629 // Hmm, the LPC server thread is hung somewhere, 00630 // press on 00631 // 00632 } 00633 00634 RtlpLpcLockServer( Server ); 00635 00636 NtClose( Server->ShutdownEvent ); 00637 00638 Server->ShutdownEvent = NULL ; 00639 00640 } 00641 else 00642 { 00643 Server->Flags |= LPCSVR_SHUTDOWN_PENDING ; 00644 } 00645 00646 // 00647 // The server object is locked, and there are no receives 00648 // pending. Or, the receives appear hung. Skim through the 00649 // context list, calling the server code. The disconnect 00650 // message is NULL, indicating that this is a server initiated 00651 // shutdown. 00652 // 00653 00654 00655 while ( ! IsListEmpty( &Server->ContextList ) ) 00656 { 00657 Scan = RemoveHeadList( &Server->ContextList ); 00658 00659 Context = CONTAINING_RECORD( Scan, LPCSVR_CONTEXT, List ); 00660 00661 Status = Server->Init.RundownFn( 00662 Context->PrivateContext, 00663 NULL ); 00664 00665 Context->List.Flink = NULL ; 00666 00667 RtlpLpcDerefContext( Context, NULL ); 00668 00669 } 00670 00671 // 00672 // All contexts have been deleted: clean up the messages 00673 // 00674 00675 while ( Server->MessagePool ) 00676 { 00677 Message = Server->MessagePool ; 00678 00679 Server->MessagePool = Message ; 00680 00681 RtlFreeHeap( RtlProcessHeap(), 00682 0, 00683 Message ); 00684 } 00685 00686 00687 // 00688 // Clean up server objects 00689 // 00690 00691 return(STATUS_SUCCESS); 00692 00693 }


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