00038 :
00039
00040 This
procedure is used by
the server process to wait
for a message from a
00041 client process
00042
00043
A client and server process can receive messages
using the
00044
NtReplyWaitReceivePort service:
00045
00046 If
the ReplyMessage parameter
is specified, then
the reply will be sent
00047
using NtReplyPort.
00048
00049 If
the PortHandle parameter specifies a connection port, then
the receive
00050 will
return whenever a message
is sent to a server communication port that
00051 does not have its own receive queue and
the message
is therefore queued to
00052
the receive queue of
the connection port.
00053
00054 If
the PortHandle parameter specifies a server communication port that
00055 does not have a receive queue, then behaves as
if the associated
00056 connection port handle was specified. Otherwise
the receive will
return
00057 whenever message
is placed in
the receive queue associated with
the
00058 server communication port.
00059
00060 The received message will be returned in
the variable specified by
the
00061 ReceiveMessage parameter. If
the MapInfoOffset field of
the reply message
00062
is non-zero, then
the PORT_MAP_INFORMATION structure
it points to will be
00063 processed and
the relevant pages will be mapped into
the caller's address
00064 space. The service returns an error
if there
is not enough room in
the
00065 caller's address space to accomodate
the mappings.
00066
00067 Arguments:
00068
00069
PortHandle - Specifies
the handle of
the connection or communication port
00070 to
do the receive from.
00071
00072 PortContext - Specifies an optional pointer to a variable that
is to
00073 receive
the context value associated with
the communication port that
00074
the message
is being received from. This context variable was
00075 specified on
the call to
the NtAcceptConnectPort service.
00076
00077
ReplyMessage - This optional parameter specifies
the address of a reply
00078 message to be sent. The ClientId and MessageId fields determine which
00079 thread will get
the reply. See description of
NtReplyPort for how
the
00080 reply
is sent. The reply
is sent before blocking
for the receive.
00081
00082 ReceiveMessage - Specifies
the address of a variable to receive
the
00083 message.
00084
00085 Return Value:
00086
00087
Status code that indicates whether or not
the operation was successful.
00088
00089 --*/
00090
00091 {
00092
PLPCP_PORT_OBJECT PortObject;
00093
PLPCP_PORT_OBJECT ReceivePort;
00094 PORT_MESSAGE CapturedReplyMessage;
00095
KPROCESSOR_MODE PreviousMode;
00096
KPROCESSOR_MODE WaitMode;
00097
NTSTATUS Status;
00098
PLPCP_MESSAGE Msg;
00099
PETHREAD CurrentThread;
00100
PETHREAD WakeupThread;
00101
00102
PAGED_CODE();
00103
00104 CurrentThread =
PsGetCurrentThread();
00105
00106
00107
00108
00109
00110 PreviousMode = KeGetPreviousMode();
00111 WaitMode = PreviousMode;
00112
00113
if (PreviousMode !=
KernelMode) {
00114
00115
try {
00116
00117
if (ARGUMENT_PRESENT( PortContext )) {
00118
00119
ProbeForWriteUlong( (PULONG)PortContext );
00120 }
00121
00122
if (ARGUMENT_PRESENT( ReplyMessage)) {
00123
00124
ProbeForRead( ReplyMessage,
00125
sizeof( *ReplyMessage ),
00126
sizeof( ULONG ));
00127
00128 CapturedReplyMessage = *
ReplyMessage;
00129 }
00130
00131
ProbeForWrite( ReceiveMessage,
00132
sizeof( *ReceiveMessage ),
00133
sizeof( ULONG ));
00134
00135 } except( EXCEPTION_EXECUTE_HANDLER ) {
00136
00137
return GetExceptionCode();
00138 }
00139
00140 }
else {
00141
00142
00143
00144
00145
00146
00147
00148
if (
IS_SYSTEM_THREAD(CurrentThread) ) {
00149
00150 WaitMode =
UserMode;
00151 }
00152
00153
if (ARGUMENT_PRESENT( ReplyMessage )) {
00154
00155 CapturedReplyMessage = *
ReplyMessage;
00156 }
00157 }
00158
00159
if (ARGUMENT_PRESENT( ReplyMessage )) {
00160
00161
00162
00163
00164
00165
00166
if ((((CLONG)CapturedReplyMessage.u1.s1.DataLength) +
sizeof( PORT_MESSAGE )) >
00167 ((CLONG)CapturedReplyMessage.u1.s1.TotalLength)) {
00168
00169
return STATUS_INVALID_PARAMETER;
00170 }
00171
00172
00173
00174
00175
00176
if (CapturedReplyMessage.MessageId == 0) {
00177
00178
return STATUS_INVALID_PARAMETER;
00179 }
00180 }
00181
00182
00183
00184
00185
00186
00187
Status =
LpcpReferencePortObject( PortHandle,
00188 0,
00189 PreviousMode,
00190 &PortObject );
00191
00192
if (!
NT_SUCCESS( Status )) {
00193
00194
Status =
ObReferenceObjectByHandle( PortHandle,
00195 0,
00196 LpcWaitablePortObjectType,
00197 PreviousMode,
00198 &PortObject,
00199 NULL );
00200
00201
if ( !
NT_SUCCESS( Status )) {
00202
00203
return Status;
00204 }
00205 }
00206
00207
LpcpSaveThread (PortObject);
00208
00209
00210
00211
00212
00213
if (ARGUMENT_PRESENT( ReplyMessage )) {
00214
00215
if (((ULONG)CapturedReplyMessage.u1.s1.TotalLength > PortObject->
MaxMessageLength) ||
00216 ((ULONG)CapturedReplyMessage.u1.s1.TotalLength <= (ULONG)CapturedReplyMessage.u1.s1.DataLength)) {
00217
00218
ObDereferenceObject( PortObject );
00219
00220
return STATUS_PORT_MESSAGE_TOO_LONG;
00221 }
00222 }
00223
00224
00225
00226
00227
00228
00229
00230
if ((PortObject->
Flags &
PORT_TYPE) !=
CLIENT_COMMUNICATION_PORT) {
00231
00232 ReceivePort = PortObject->
ConnectionPort;
00233
00234 }
else {
00235
00236 ReceivePort = PortObject;
00237 }
00238
00239
00240
00241
00242
00243
if (ARGUMENT_PRESENT( ReplyMessage )) {
00244
00245
00246
00247
00248
00249
00250
00251
Status =
PsLookupProcessThreadByCid( &CapturedReplyMessage.ClientId,
00252 NULL,
00253 &WakeupThread );
00254
00255
if (!
NT_SUCCESS( Status )) {
00256
00257
ObDereferenceObject( PortObject );
00258
return Status;
00259 }
00260
00261
00262
00263
00264
00265
00266
00267
LpcpAcquireLpcpLock();
00268
00269 Msg = (
PLPCP_MESSAGE)
LpcpAllocateFromPortZone( CapturedReplyMessage.u1.s1.TotalLength );
00270
00271
if (Msg ==
NULL) {
00272
00273
LpcpReleaseLpcpLock();
00274
00275
ObDereferenceObject( WakeupThread );
00276
ObDereferenceObject( PortObject );
00277
00278
return STATUS_NO_MEMORY;
00279 }
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
if ((WakeupThread->
LpcReplyMessageId != CapturedReplyMessage.MessageId)
00293
00294 ||
00295
00296 ((WakeupThread->
LpcReplyMessage !=
NULL) &&
00297 (((
PLPCP_MESSAGE)(WakeupThread->
LpcReplyMessage))->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) != LPC_REQUEST)) {
00298
00299
LpcpPrint((
"%s Attempted ReplyWaitReceive to Thread %lx (%s)\n",
00300
PsGetCurrentProcess()->ImageFileName,
00301 WakeupThread,
00302
THREAD_TO_PROCESS( WakeupThread )->ImageFileName ));
00303
00304
LpcpPrint((
"failed. MessageId == %u Client Id: %x.%x\n",
00305 CapturedReplyMessage.MessageId,
00306 CapturedReplyMessage.ClientId.UniqueProcess,
00307 CapturedReplyMessage.ClientId.UniqueThread ));
00308
00309
LpcpPrint((
" Thread MessageId == %u Client Id: %x.%x\n",
00310 WakeupThread->
LpcReplyMessageId,
00311 WakeupThread->
Cid.UniqueProcess,
00312 WakeupThread->
Cid.UniqueThread ));
00313
00314
#if DBG
00315
if (LpcpStopOnReplyMismatch) {
00316
00317 DbgBreakPoint();
00318 }
00319
#endif
00320
00321
LpcpFreeToPortZone( Msg, TRUE );
00322
00323
LpcpReleaseLpcpLock();
00324
00325
ObDereferenceObject( WakeupThread );
00326
ObDereferenceObject( PortObject );
00327
00328
return STATUS_REPLY_MESSAGE_MISMATCH;
00329 }
00330
00331
00332
00333
00334
00335
00336
00337
try {
00338
00339
LpcpMoveMessage( &Msg->
Request,
00340 &CapturedReplyMessage,
00341 (ReplyMessage + 1),
00342 LPC_REPLY,
00343 NULL );
00344
00345 } except( EXCEPTION_EXECUTE_HANDLER ) {
00346
00347
LpcpFreeToPortZone( Msg, TRUE );
00348
00349
LpcpReleaseLpcpLock();
00350
00351
ObDereferenceObject( WakeupThread );
00352
ObDereferenceObject( PortObject );
00353
00354
return (
Status = GetExceptionCode());
00355 }
00356
00357
LpcpTrace((
"%s Sending Reply Msg %lx (%u.%u, %x) [%08x %08x %08x %08x] to Thread %lx (%s)\n",
00358
PsGetCurrentProcess()->ImageFileName,
00359 Msg,
00360 CapturedReplyMessage.MessageId,
00361 CapturedReplyMessage.CallbackId,
00362 CapturedReplyMessage.u2.s2.DataInfoOffset,
00363 *((PULONG)(Msg+1)+0),
00364 *((PULONG)(Msg+1)+1),
00365 *((PULONG)(Msg+1)+2),
00366 *((PULONG)(Msg+1)+3),
00367 WakeupThread,
00368
THREAD_TO_PROCESS( WakeupThread )->ImageFileName ));
00369
00370
00371
00372
00373
00374
00375
00376
LpcpFreeDataInfoMessage( PortObject,
00377 CapturedReplyMessage.MessageId,
00378 CapturedReplyMessage.CallbackId );
00379
00380
00381
00382
00383
00384
00385
ObReferenceObject( WakeupThread );
00386
00387
00388
00389
00390
00391
00392 Msg->RepliedToThread = WakeupThread;
00393
00394 WakeupThread->
LpcReplyMessageId = 0;
00395 WakeupThread->
LpcReplyMessage = (PVOID)Msg;
00396
00397
00398
00399
00400
00401
if (!WakeupThread->
LpcExitThreadCalled && !IsListEmpty( &WakeupThread->
LpcReplyChain )) {
00402
00403 RemoveEntryList( &WakeupThread->
LpcReplyChain );
00404
00405 InitializeListHead( &WakeupThread->
LpcReplyChain );
00406 }
00407
00408
if ((CurrentThread->
LpcReceivedMsgIdValid) &&
00409 (CurrentThread->
LpcReceivedMessageId == CapturedReplyMessage.MessageId)) {
00410
00411 CurrentThread->
LpcReceivedMessageId = 0;
00412
00413 CurrentThread->
LpcReceivedMsgIdValid =
FALSE;
00414 }
00415
00416
LpcpTrace((
"%s Waiting for message to Port %x (%s)\n",
00417
PsGetCurrentProcess()->ImageFileName,
00418 ReceivePort,
00419
LpcpGetCreatorName( ReceivePort )));
00420
00421
LpcpReleaseLpcpLock();
00422
00423
00424
00425
00426
00427
00428
KeReleaseSemaphore( &WakeupThread->
LpcReplySemaphore,
00429 1,
00430 1,
00431 FALSE );
00432
00433
ObDereferenceObject( WakeupThread );
00434
00435
Status =
KeWaitForSingleObject( ReceivePort->
MsgQueue.
Semaphore,
00436 WrLpcReceive,
00437 WaitMode,
00438 FALSE,
00439 NULL );
00440
00441
00442
00443
00444
00445
00446 }
else {
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
LpcpTrace((
"%s Waiting for message to Port %x (%s)\n",
00459
PsGetCurrentProcess()->ImageFileName,
00460 ReceivePort,
00461
LpcpGetCreatorName( ReceivePort )));
00462
00463
Status =
KeWaitForSingleObject( ReceivePort->
MsgQueue.
Semaphore,
00464 WrLpcReceive,
00465 WaitMode,
00466 FALSE,
00467 NULL );
00468 }
00469
00470
00471
00472
00473
00474
if (
Status == STATUS_SUCCESS) {
00475
00476
LpcpAcquireLpcpLock();
00477
00478
00479
00480
00481
00482
if (IsListEmpty( &ReceivePort->
MsgQueue.
ReceiveHead )) {
00483
00484
if ( ReceivePort->
Flags &
PORT_WAITABLE ) {
00485
00486
KeResetEvent( &ReceivePort->
WaitEvent );
00487 }
00488
00489
LpcpReleaseLpcpLock();
00490
00491
ObDereferenceObject( PortObject );
00492
00493
return STATUS_UNSUCCESSFUL;
00494 }
00495
00496
00497
00498
00499
00500 Msg = (
PLPCP_MESSAGE)RemoveHeadList( &ReceivePort->
MsgQueue.
ReceiveHead );
00501
00502
if ( IsListEmpty( &ReceivePort->
MsgQueue.
ReceiveHead)) {
00503
00504
if ( ReceivePort->
Flags &
PORT_WAITABLE ) {
00505
00506
KeResetEvent( &ReceivePort->
WaitEvent );
00507 }
00508 }
00509
00510 InitializeListHead( &Msg->Entry );
00511
00512
LpcpTrace((
"%s Receive Msg %lx (%u) from Port %lx (%s)\n",
00513
PsGetCurrentProcess()->ImageFileName,
00514 Msg,
00515 Msg->Request.MessageId,
00516 ReceivePort,
00517
LpcpGetCreatorName( ReceivePort )));
00518
00519
00520
00521
00522
00523
00524 CurrentThread->
LpcReceivedMessageId = Msg->Request.MessageId;
00525 CurrentThread->
LpcReceivedMsgIdValid =
TRUE;
00526
00527
LpcpReleaseLpcpLock();
00528
00529
try {
00530
00531
00532
00533
00534
00535
if ((Msg->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) == LPC_CONNECTION_REQUEST) {
00536
00537
PLPCP_CONNECTION_MESSAGE ConnectMsg;
00538 ULONG ConnectionInfoLength;
00539
PLPCP_MESSAGE TempMsg;
00540
00541 ConnectMsg = (
PLPCP_CONNECTION_MESSAGE)(Msg + 1);
00542
00543 ConnectionInfoLength = Msg->Request.u1.s1.DataLength -
sizeof( *ConnectMsg );
00544
00545
00546
00547
00548
00549
00550 TempMsg = Msg;
00551 Msg =
NULL;
00552
00553 *ReceiveMessage = TempMsg->
Request;
00554
00555 ReceiveMessage->u1.s1.TotalLength = (CSHORT)(
sizeof( *ReceiveMessage ) + ConnectionInfoLength);
00556 ReceiveMessage->u1.s1.DataLength = (CSHORT)ConnectionInfoLength;
00557
00558 RtlMoveMemory( ReceiveMessage+1,
00559 ConnectMsg + 1,
00560 ConnectionInfoLength );
00561
00562
if (ARGUMENT_PRESENT( PortContext )) {
00563
00564 *PortContext =
NULL;
00565 }
00566
00567
00568
00569
00570
00571 }
else if ((Msg->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) != LPC_REPLY) {
00572
00573
LpcpMoveMessage( ReceiveMessage,
00574 &Msg->Request,
00575 (&Msg->Request) + 1,
00576 0,
00577 NULL );
00578
00579
if (ARGUMENT_PRESENT( PortContext )) {
00580
00581 *PortContext = Msg->PortContext;
00582 }
00583
00584
00585
00586
00587
00588
00589
00590
if (Msg->Request.u2.s2.DataInfoOffset != 0) {
00591
00592
LpcpSaveDataInfoMessage( PortObject, Msg );
00593 Msg =
NULL;
00594 }
00595
00596
00597
00598
00599
00600 }
else {
00601
00602
LpcpPrint((
"LPC: Bogus reply message (%08x) in receive queue of connection port %08x\n",
00603 Msg, ReceivePort ));
00604
00605 KdBreakPoint();
00606 }
00607
00608 } except( EXCEPTION_EXECUTE_HANDLER ) {
00609
00610
Status = GetExceptionCode();
00611 }
00612
00613
00614
00615
00616
00617
00618
00619
if (Msg !=
NULL) {
00620
00621
LpcpFreeToPortZone( Msg, FALSE );
00622 }
00623 }
00624
00625
ObDereferenceObject( PortObject );
00626
00627
00628
00629
00630
00631
return Status;
00632 }