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

lpcsvr.c

Go to the documentation of this file.
00001 //+--------------------------------------------------------------------------- 00002 // 00003 // Microsoft Windows 00004 // Copyright (C) Microsoft Corporation, 1992 - 1997. 00005 // 00006 // File: lpcsvr.c 00007 // 00008 // Contents: 00009 // 00010 // Classes: 00011 // 00012 // Functions: 00013 // 00014 // History: 12-12-97 RichardW Created 00015 // 00016 //---------------------------------------------------------------------------- 00017 00018 #include <ntos.h> 00019 #include <nt.h> 00020 #include <ntrtl.h> 00021 #include <nturtl.h> 00022 #include "lpcsvr.h" 00023 00024 #define RtlpLpcLockServer( s ) RtlEnterCriticalSection( &s->Lock ); 00025 #define RtlpLpcUnlockServer( s ) RtlLeaveCriticalSection( &s->Lock ); 00026 00027 #define RtlpLpcContextFromClient( p ) ( CONTAINING_RECORD( p, LPCSVR_CONTEXT, PrivateContext ) ) 00028 00029 //+--------------------------------------------------------------------------- 00030 // 00031 // Function: RtlpLpcDerefContext 00032 // 00033 // Synopsis: Deref the context. If this context is being cleaned up after 00034 // the server has been deleted, then the message is freed directly, 00035 // rather than being released to the general queue. 00036 // 00037 // Arguments: [Context] -- 00038 // [Message] -- 00039 // 00040 // History: 2-06-98 RichardW Created 00041 // 00042 // Notes: 00043 // 00044 //---------------------------------------------------------------------------- 00045 VOID 00046 RtlpLpcDerefContext( 00047 PLPCSVR_CONTEXT Context, 00048 PLPCSVR_MESSAGE Message 00049 ) 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 } 00117 00118 //+--------------------------------------------------------------------------- 00119 // 00120 // Function: RtlpLpcWorkerThread 00121 // 00122 // Synopsis: General worker thread 00123 // 00124 // Arguments: [Parameter] -- 00125 // 00126 // History: 2-06-98 RichardW Created 00127 // 00128 // Notes: 00129 // 00130 //---------------------------------------------------------------------------- 00131 00132 00133 VOID 00134 RtlpLpcWorkerThread( 00135 PVOID Parameter 00136 ) 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 } 00258 00259 VOID 00260 RtlpLpcServerCallback( 00261 PVOID Parameter, 00262 BOOLEAN TimedOut 00263 ) 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 } 00461 00462 NTSTATUS 00463 RtlCreateLpcServer( 00464 POBJECT_ATTRIBUTES PortName, 00465 PLPCSVR_INITIALIZE Init, 00466 PLARGE_INTEGER IdleTimeout, 00467 ULONG MessageSize, 00468 ULONG Options, 00469 PVOID * LpcServer 00470 ) 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 } 00549 00550 00551 NTSTATUS 00552 RtlShutdownLpcServer( 00553 PVOID LpcServer 00554 ) 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 } 00694 00695 NTSTATUS 00696 RtlImpersonateLpcClient( 00697 PVOID Context, 00698 PPORT_MESSAGE Message 00699 ) 00700 { 00701 PLPCSVR_CONTEXT LpcContext ; 00702 00703 LpcContext = RtlpLpcContextFromClient( Context ); 00704 00705 return NtImpersonateClientOfPort( 00706 LpcContext->CommPort, 00707 Message ); 00708 00709 } 00710 00711 NTSTATUS 00712 RtlCallbackLpcClient( 00713 PVOID Context, 00714 PPORT_MESSAGE Request, 00715 PPORT_MESSAGE Callback 00716 ) 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 }

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