00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
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
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
00121
00122
00123
00124
00125
00126
00127
00128
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
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
00185
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
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
00246
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
00338
00339
00340
if (
Status == STATUS_TIMEOUT )
00341 {
00342
00343
00344
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
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
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
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
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
00590
00591
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
00630
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
00648
00649
00650
00651
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
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
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 }