You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1633 lines
36 KiB
1633 lines
36 KiB
/*++
|
|
|
|
Copyright (c) 1999-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
channel.c
|
|
|
|
Abstract:
|
|
|
|
Routines for managing channels in the sac.
|
|
|
|
Author:
|
|
|
|
Brian Guarraci (briangu) March, 2001.
|
|
Sean Selitrennikoff (v-seans) Sept, 2000.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "sac.h"
|
|
|
|
BOOLEAN
|
|
ChannelIsValidType(
|
|
SAC_CHANNEL_TYPE ChannelType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is a convenience routine to determine if a the given type
|
|
is a valid Channel type
|
|
|
|
Arguments:
|
|
|
|
ChannelType - the type to be investigated
|
|
|
|
Return Value:
|
|
|
|
TRUE - if type is valid
|
|
|
|
otherwise, FALSE
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN isValid;
|
|
|
|
switch(ChannelType) {
|
|
case ChannelTypeVTUTF8:
|
|
case ChannelTypeRaw:
|
|
case ChannelTypeCmd:
|
|
isValid = TRUE;
|
|
break;
|
|
default:
|
|
isValid = FALSE;
|
|
break;
|
|
}
|
|
|
|
return isValid;
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
ChannelIsActive(
|
|
IN PSAC_CHANNEL Channel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine if a channel is active.
|
|
|
|
Arguments:
|
|
|
|
Channel - Channel to see if has new data
|
|
|
|
Return Value:
|
|
|
|
TRUE - if the channel is active
|
|
|
|
otherwise, FALSE
|
|
|
|
--*/
|
|
{
|
|
SAC_CHANNEL_STATUS Status;
|
|
|
|
ChannelGetStatus(
|
|
Channel,
|
|
&Status
|
|
);
|
|
|
|
return (BOOLEAN)(Status == ChannelStatusActive);
|
|
}
|
|
|
|
BOOLEAN
|
|
ChannelIsEqual(
|
|
IN PSAC_CHANNEL Channel,
|
|
IN PSAC_CHANNEL_HANDLE Handle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine if a channel is the same as the one in question
|
|
|
|
Note: this is to encapsulate the GUID implementation of
|
|
channel handles
|
|
|
|
Arguments:
|
|
|
|
Channel - Channel to see if has new data
|
|
ChannelHandle - The channel handle in question
|
|
|
|
Return Value:
|
|
|
|
TRUE - if the channel is active
|
|
|
|
otherwise, FALSE
|
|
|
|
--*/
|
|
{
|
|
|
|
return (BOOLEAN)IsEqualGUID(
|
|
&(ChannelGetHandle(Channel).ChannelHandle),
|
|
&(Handle->ChannelHandle)
|
|
);
|
|
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
ChannelIsClosed(
|
|
IN PSAC_CHANNEL Channel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine if a channel is available for reuse. The criterion
|
|
for reuse are:
|
|
|
|
1. The channel must be inactive
|
|
2. If the preserve bit is FALSE, then HasNewData must == FALSE
|
|
|
|
Arguments:
|
|
|
|
Channel - Channel to see if has new data
|
|
|
|
Return Value:
|
|
|
|
TRUE - if the channel has unsent data
|
|
|
|
otherwise, FALSE
|
|
|
|
--*/
|
|
{
|
|
SAC_CHANNEL_STATUS Status;
|
|
|
|
ChannelGetStatus(
|
|
Channel,
|
|
&Status
|
|
);
|
|
|
|
return (BOOLEAN)(
|
|
(Status == ChannelStatusInactive) &&
|
|
(ChannelHasNewOBufferData(Channel) == FALSE)
|
|
);
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelInitializeVTable(
|
|
IN PSAC_CHANNEL Channel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine assigns channel type specific functions.
|
|
|
|
Arguments:
|
|
|
|
Channel - The channel to assign the functions to.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful, else the appropriate error code.
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// Fill out the channel's vtable according to channel type
|
|
//
|
|
|
|
switch(ChannelGetType(Channel)){
|
|
case ChannelTypeVTUTF8:
|
|
|
|
Channel->Create = VTUTF8ChannelCreate;
|
|
Channel->Destroy = VTUTF8ChannelDestroy;
|
|
Channel->OFlush = VTUTF8ChannelOFlush;
|
|
Channel->OEcho = VTUTF8ChannelOEcho;
|
|
Channel->OWrite = VTUTF8ChannelOWrite;
|
|
Channel->ORead = VTUTF8ChannelORead;
|
|
Channel->IWrite = VTUTF8ChannelIWrite;
|
|
Channel->IRead = VTUTF8ChannelIRead;
|
|
Channel->IReadLast = VTUTF8ChannelIReadLast;
|
|
Channel->IBufferIsFull = VTUTF8ChannelIBufferIsFull;
|
|
Channel->IBufferLength = VTUTF8ChannelIBufferLength;
|
|
|
|
break;
|
|
case ChannelTypeRaw:
|
|
|
|
Channel->Create = RawChannelCreate;
|
|
Channel->Destroy = RawChannelDestroy;
|
|
Channel->OFlush = RawChannelOFlush;
|
|
Channel->OEcho = RawChannelOEcho;
|
|
Channel->OWrite = RawChannelOWrite;
|
|
Channel->ORead = RawChannelORead;
|
|
Channel->IWrite = RawChannelIWrite;
|
|
Channel->IRead = RawChannelIRead;
|
|
Channel->IReadLast = RawChannelIReadLast;
|
|
Channel->IBufferIsFull = RawChannelIBufferIsFull;
|
|
Channel->IBufferLength = RawChannelIBufferLength;
|
|
|
|
break;
|
|
|
|
case ChannelTypeCmd:
|
|
|
|
Channel->Create = CmdChannelCreate;
|
|
Channel->Destroy = CmdChannelDestroy;
|
|
Channel->OFlush = CmdChannelOFlush;
|
|
Channel->OEcho = VTUTF8ChannelOEcho;
|
|
Channel->OWrite = CmdChannelOWrite;
|
|
Channel->ORead = CmdChannelORead;
|
|
Channel->IWrite = VTUTF8ChannelIWrite;
|
|
Channel->IRead = VTUTF8ChannelIRead;
|
|
Channel->IReadLast = VTUTF8ChannelIReadLast;
|
|
Channel->IBufferIsFull = VTUTF8ChannelIBufferIsFull;
|
|
Channel->IBufferLength = VTUTF8ChannelIBufferLength;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
break;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelCreate(
|
|
OUT PSAC_CHANNEL Channel,
|
|
IN PSAC_CHANNEL_OPEN_ATTRIBUTES Attributes,
|
|
IN SAC_CHANNEL_HANDLE Handle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine allocates a channel and returns a pointer to it.
|
|
|
|
Arguments:
|
|
|
|
Channel - The resulting channel.
|
|
Attributes - All the parameters for the new channel
|
|
Handle - The new channel's handle
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful, else the appropriate error code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
BOOLEAN b;
|
|
PVOID EventObjectBody;
|
|
PVOID EventWaitObjectBody;
|
|
|
|
ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1);
|
|
ASSERT_STATUS(Attributes, STATUS_INVALID_PARAMETER_2);
|
|
|
|
//
|
|
// Verify that if the user wants to use the CLOSE_EVENT, we received on to use
|
|
//
|
|
if (Attributes->Flags & SAC_CHANNEL_FLAG_CLOSE_EVENT) {
|
|
ASSERT_STATUS(Attributes->CloseEvent != NULL, STATUS_INVALID_PARAMETER);
|
|
} else {
|
|
ASSERT_STATUS(Attributes->CloseEvent == NULL, STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// Verify that if the user wants to use the HAS_NEW_DATA_EVENT, we received one to use
|
|
//
|
|
if (Attributes->Flags & SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT) {
|
|
ASSERT_STATUS(Attributes->HasNewDataEvent != NULL, STATUS_INVALID_PARAMETER);
|
|
} else {
|
|
ASSERT_STATUS(Attributes->HasNewDataEvent == NULL, STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
#if ENABLE_CHANNEL_LOCKING
|
|
//
|
|
// Verify that if the user wants to use the LOCK_EVENT, we received one to use
|
|
//
|
|
if (Attributes->Flags & SAC_CHANNEL_FLAG_LOCK_EVENT) {
|
|
ASSERT_STATUS(Attributes->LockEvent != NULL, STATUS_INVALID_PARAMETER);
|
|
} else {
|
|
ASSERT_STATUS(Attributes->LockEvent == NULL, STATUS_INVALID_PARAMETER);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Verify that if the user wants to use the LOCK_EVENT, we received one to use
|
|
//
|
|
if (Attributes->Flags & SAC_CHANNEL_FLAG_REDRAW_EVENT) {
|
|
ASSERT_STATUS(Attributes->RedrawEvent != NULL, STATUS_INVALID_PARAMETER);
|
|
} else {
|
|
ASSERT_STATUS(Attributes->RedrawEvent == NULL, STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// Initialize the channel structure
|
|
//
|
|
do {
|
|
|
|
//
|
|
// Initialize the channel structure
|
|
//
|
|
RtlZeroMemory(Channel, sizeof(SAC_CHANNEL));
|
|
|
|
//
|
|
// Initialize the channel access locks
|
|
//
|
|
INIT_CHANNEL_LOCKS(Channel);
|
|
|
|
//
|
|
// copy the name and force NULL termination at the end of the buffer
|
|
//
|
|
ChannelSetName(
|
|
Channel,
|
|
Attributes->Name
|
|
);
|
|
|
|
//
|
|
// copy the description and force NULL termination at the end of the buffer
|
|
//
|
|
ChannelSetDescription(
|
|
Channel,
|
|
Attributes->Description
|
|
);
|
|
|
|
//
|
|
// Attempt to get the wait object from the event
|
|
//
|
|
if (Attributes->CloseEvent) {
|
|
|
|
b = VerifyEventWaitable(
|
|
Attributes->CloseEvent,
|
|
&EventObjectBody,
|
|
&EventWaitObjectBody
|
|
);
|
|
|
|
if(!b) {
|
|
Status = STATUS_INVALID_HANDLE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// We successfully got the wait object, so keep it.
|
|
//
|
|
Channel->CloseEvent = Attributes->CloseEvent;
|
|
Channel->CloseEventObjectBody = EventObjectBody;
|
|
Channel->CloseEventWaitObjectBody = EventWaitObjectBody;
|
|
|
|
}
|
|
|
|
//
|
|
// Attempt to get the wait object from the event
|
|
//
|
|
if (Attributes->HasNewDataEvent) {
|
|
|
|
b = VerifyEventWaitable(
|
|
Attributes->HasNewDataEvent,
|
|
&EventObjectBody,
|
|
&EventWaitObjectBody
|
|
);
|
|
|
|
if(!b) {
|
|
Status = STATUS_INVALID_HANDLE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// We successfully got the wait object, so keep it.
|
|
//
|
|
Channel->HasNewDataEvent = Attributes->HasNewDataEvent;
|
|
Channel->HasNewDataEventObjectBody = EventObjectBody;
|
|
Channel->HasNewDataEventWaitObjectBody = EventWaitObjectBody;
|
|
|
|
}
|
|
|
|
#if ENABLE_CHANNEL_LOCKING
|
|
//
|
|
// Attempt to get the wait object from the event
|
|
//
|
|
if (Attributes->LockEvent) {
|
|
|
|
b = VerifyEventWaitable(
|
|
Attributes->LockEvent,
|
|
&EventObjectBody,
|
|
&EventWaitObjectBody
|
|
);
|
|
|
|
if(!b) {
|
|
Status = STATUS_INVALID_HANDLE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// We successfully got the wait object, so keep it.
|
|
//
|
|
Channel->LockEvent = Attributes->LockEvent;
|
|
Channel->LockEventObjectBody = EventObjectBody;
|
|
Channel->LockEventWaitObjectBody = EventWaitObjectBody;
|
|
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Attempt to get the wait object from the event
|
|
//
|
|
if (Attributes->RedrawEvent) {
|
|
|
|
b = VerifyEventWaitable(
|
|
Attributes->RedrawEvent,
|
|
&EventObjectBody,
|
|
&EventWaitObjectBody
|
|
);
|
|
|
|
if(!b) {
|
|
Status = STATUS_INVALID_HANDLE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// We successfully got the wait object, so keep it.
|
|
//
|
|
Channel->RedrawEvent = Attributes->RedrawEvent;
|
|
Channel->RedrawEventObjectBody = EventObjectBody;
|
|
Channel->RedrawEventWaitObjectBody = EventWaitObjectBody;
|
|
|
|
}
|
|
|
|
//
|
|
// Copy the remaining attributes
|
|
//
|
|
// Note: use the channel handle sent to use by the channel manager
|
|
//
|
|
Channel->Handle = Handle;
|
|
Channel->Type = Attributes->Type;
|
|
Channel->Flags = Attributes->Flags;
|
|
|
|
//
|
|
// If we have the ApplicationType,
|
|
// then save it
|
|
//
|
|
if (Attributes->Flags & SAC_CHANNEL_FLAG_APPLICATION_TYPE) {
|
|
Channel->ApplicationType = Attributes->ApplicationType;
|
|
}
|
|
|
|
//
|
|
// Assign the appropriate channel functions base on type
|
|
//
|
|
Status = ChannelInitializeVTable(Channel);
|
|
|
|
if (! NT_SUCCESS(Status)) {
|
|
|
|
IF_SAC_DEBUG(
|
|
SAC_DEBUG_FAILS,
|
|
KdPrint(("SAC Create Channel :: Failed to initialize vtable\n"))
|
|
);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// Do Channel type specific initialization
|
|
//
|
|
Status = Channel->Create(Channel);
|
|
|
|
if (! NT_SUCCESS(Status)) {
|
|
|
|
IF_SAC_DEBUG(
|
|
SAC_DEBUG_FAILS,
|
|
KdPrint(("SAC Create Channel :: Failed channel specific initialization\n"))
|
|
);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// The channel is now Active
|
|
//
|
|
ChannelSetStatus(Channel, ChannelStatusActive);
|
|
|
|
} while (FALSE);
|
|
|
|
//
|
|
// If the creation failed, destroy the channel object
|
|
//
|
|
if (! NT_SUCCESS(Status)) {
|
|
Channel->Destroy(Channel);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelDereferenceHandles(
|
|
PSAC_CHANNEL Channel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine dereferences and NULLs the channel's event handles,
|
|
if appropriate.
|
|
|
|
Note: caller must hold channel mutex
|
|
|
|
Arguments:
|
|
|
|
Channel - the channel to close
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - if the mapping was successful
|
|
|
|
otherwise, error status
|
|
|
|
--*/
|
|
{
|
|
ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER);
|
|
|
|
//
|
|
// Release the has new data event if we have it
|
|
//
|
|
if (Channel->HasNewDataEvent) {
|
|
|
|
//
|
|
// validate that the channel's attributes for this event
|
|
// are properly set
|
|
//
|
|
ASSERT(ChannelGetFlags(Channel) & SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT);
|
|
ASSERT(Channel->HasNewDataEventObjectBody);
|
|
ASSERT(Channel->HasNewDataEventWaitObjectBody);
|
|
|
|
if (Channel->HasNewDataEventObjectBody) {
|
|
|
|
ObDereferenceObject(Channel->HasNewDataEventObjectBody);
|
|
|
|
//
|
|
// NULL the event pointers
|
|
//
|
|
ChannelSetFlags(
|
|
Channel,
|
|
ChannelGetFlags(Channel) & ~SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT
|
|
);
|
|
Channel->HasNewDataEvent = NULL;
|
|
Channel->HasNewDataEventObjectBody = NULL;
|
|
Channel->HasNewDataEventWaitObjectBody = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// do we have the Close Channel Event?
|
|
//
|
|
if (Channel->CloseEvent) {
|
|
|
|
//
|
|
// validate that the channel's attributes for this event
|
|
// are properly set
|
|
//
|
|
ASSERT(ChannelGetFlags(Channel) & SAC_CHANNEL_FLAG_CLOSE_EVENT);
|
|
ASSERT(Channel->CloseEventObjectBody);
|
|
ASSERT(Channel->CloseEventWaitObjectBody);
|
|
|
|
if (Channel->CloseEventObjectBody) {
|
|
|
|
//
|
|
// release the events
|
|
//
|
|
ObDereferenceObject(Channel->CloseEventObjectBody);
|
|
|
|
//
|
|
// NULL the event pointers
|
|
//
|
|
ChannelSetFlags(
|
|
Channel,
|
|
ChannelGetFlags(Channel) & ~SAC_CHANNEL_FLAG_CLOSE_EVENT
|
|
);
|
|
Channel->CloseEvent = NULL;
|
|
Channel->CloseEventObjectBody = NULL;
|
|
Channel->CloseEventWaitObjectBody = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#if ENABLE_CHANNEL_LOCKING
|
|
//
|
|
// do we have the Lock Channel Event?
|
|
//
|
|
if (Channel->LockEvent) {
|
|
|
|
//
|
|
// validate that the channel's attributes for this event
|
|
// are properly set
|
|
//
|
|
ASSERT(ChannelGetFlags(Channel) & SAC_CHANNEL_FLAG_LOCK_EVENT);
|
|
ASSERT(Channel->LockEventObjectBody);
|
|
ASSERT(Channel->LockEventWaitObjectBody);
|
|
|
|
if (Channel->LockEventObjectBody) {
|
|
|
|
//
|
|
// release the events
|
|
//
|
|
ObDereferenceObject(Channel->LockEventObjectBody);
|
|
|
|
//
|
|
// NULL the event pointers
|
|
//
|
|
ChannelSetFlags(
|
|
Channel,
|
|
ChannelGetFlags(Channel) & ~SAC_CHANNEL_FLAG_LOCK_EVENT
|
|
);
|
|
Channel->LockEvent = NULL;
|
|
Channel->LockEventObjectBody = NULL;
|
|
Channel->LockEventWaitObjectBody = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// do we have the Redraw Channel Event?
|
|
//
|
|
if (Channel->RedrawEvent) {
|
|
|
|
//
|
|
// validate that the channel's attributes for this event
|
|
// are properly set
|
|
//
|
|
ASSERT(ChannelGetFlags(Channel) & SAC_CHANNEL_FLAG_REDRAW_EVENT);
|
|
ASSERT(Channel->RedrawEventObjectBody);
|
|
ASSERT(Channel->RedrawEventWaitObjectBody);
|
|
|
|
if (Channel->RedrawEventObjectBody) {
|
|
|
|
//
|
|
// release the events
|
|
//
|
|
ObDereferenceObject(Channel->RedrawEventObjectBody);
|
|
|
|
//
|
|
// NULL the event pointers
|
|
//
|
|
ChannelSetFlags(
|
|
Channel,
|
|
ChannelGetFlags(Channel) & ~SAC_CHANNEL_FLAG_REDRAW_EVENT
|
|
);
|
|
Channel->RedrawEvent = NULL;
|
|
Channel->RedrawEventObjectBody = NULL;
|
|
Channel->RedrawEventWaitObjectBody = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelClose(
|
|
PSAC_CHANNEL Channel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine closes the given channel and
|
|
fires the CloseEvent if specified
|
|
|
|
Note: caller must hold channel mutex
|
|
|
|
Arguments:
|
|
|
|
Channel - the channel to close
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - if the mapping was successful
|
|
|
|
otherwise, error status
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER);
|
|
|
|
//
|
|
// Set the channel's state to inactive
|
|
//
|
|
ChannelSetStatus(Channel, ChannelStatusInactive);
|
|
|
|
//
|
|
// do we need to fire the Close Channel Event?
|
|
//
|
|
if (ChannelGetFlags(Channel) & SAC_CHANNEL_FLAG_CLOSE_EVENT) {
|
|
|
|
ASSERT(Channel->CloseEvent);
|
|
ASSERT(Channel->CloseEventObjectBody);
|
|
ASSERT(Channel->CloseEventWaitObjectBody);
|
|
|
|
if (Channel->CloseEventWaitObjectBody) {
|
|
|
|
//
|
|
// Yes, fire the event
|
|
//
|
|
KeSetEvent(
|
|
Channel->CloseEventWaitObjectBody,
|
|
EVENT_INCREMENT,
|
|
FALSE
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Let go of any handles this channel may own
|
|
//
|
|
Status = ChannelDereferenceHandles(Channel);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ChannelDestroy(
|
|
IN PSAC_CHANNEL Channel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine does the final steps of channel destruction.
|
|
|
|
Arguments:
|
|
|
|
Channel - The channel to be closed
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful, else the appropriate error code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER);
|
|
|
|
//
|
|
// Let go of any handles this channel may own
|
|
//
|
|
Status = ChannelDereferenceHandles(Channel);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelOWrite(
|
|
IN PSAC_CHANNEL Channel,
|
|
IN PCUCHAR Buffer,
|
|
IN ULONG BufferSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the common entry point for all channel owrite methods.
|
|
The purpose of this entry point is to provide a uniform locking
|
|
scheme for the obuffer. Channel apps should not call the owrite method
|
|
directly, but should use this instead.
|
|
|
|
Arguments:
|
|
|
|
Channel - Previously created channel.
|
|
Buffer - The buffer to write
|
|
BufferSize - The size of the buffer to write
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Make sure the caller isn't sending an unacceptably
|
|
// large sized buffer. This prevents an app from blocking
|
|
// the console manager from being blocked while a channel
|
|
// dumps it's buffer.
|
|
//
|
|
ASSERT_STATUS(
|
|
BufferSize < CHANNEL_MAX_OWRITE_BUFFER_SIZE,
|
|
STATUS_INVALID_PARAMETER_3
|
|
);
|
|
|
|
LOCK_CHANNEL_OBUFFER(Channel);
|
|
|
|
Status = Channel->OWrite(
|
|
Channel,
|
|
Buffer,
|
|
BufferSize
|
|
);
|
|
|
|
UNLOCK_CHANNEL_OBUFFER(Channel);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelOFlush(
|
|
IN PSAC_CHANNEL Channel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the common entry point for all channel OFlush methods.
|
|
The purpose of this entry point is to provide a uniform locking
|
|
scheme for the obuffer. Channel apps should not call the OFlush method
|
|
directly, but should use this instead.
|
|
|
|
Arguments:
|
|
|
|
Channel - Previously created channel.
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
LOCK_CHANNEL_OBUFFER(Channel);
|
|
|
|
Status = Channel->OFlush(Channel);
|
|
|
|
UNLOCK_CHANNEL_OBUFFER(Channel);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelOEcho(
|
|
IN PSAC_CHANNEL Channel,
|
|
IN PCUCHAR Buffer,
|
|
IN ULONG BufferSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the common entry point for all channel OEcho methods.
|
|
The purpose of this entry point is to provide a uniform locking
|
|
scheme for the obuffer. Channel apps should not call the OEcho method
|
|
directly, but should use this instead.
|
|
|
|
Arguments:
|
|
|
|
Channel - Previously created channel.
|
|
Buffer - The buffer to write
|
|
BufferSize - The size of the buffer to write
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
LOCK_CHANNEL_OBUFFER(Channel);
|
|
|
|
Status = Channel->OEcho(
|
|
Channel,
|
|
Buffer,
|
|
BufferSize
|
|
);
|
|
|
|
UNLOCK_CHANNEL_OBUFFER(Channel);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelORead(
|
|
IN PSAC_CHANNEL Channel,
|
|
IN PUCHAR Buffer,
|
|
IN ULONG BufferSize,
|
|
OUT PULONG ByteCount
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the common entry point for all channel ORead methods.
|
|
The purpose of this entry point is to provide a uniform locking
|
|
scheme for the obuffer. Channel apps should not call the ORead method
|
|
directly, but should use this instead.
|
|
|
|
Arguments:
|
|
|
|
Channel - Previously created channel.
|
|
Buffer - The buffer to write
|
|
BufferSize - The size of the buffer to write
|
|
ByteCount - The number bytes read
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
LOCK_CHANNEL_OBUFFER(Channel);
|
|
|
|
Status = Channel->ORead(
|
|
Channel,
|
|
Buffer,
|
|
BufferSize,
|
|
ByteCount
|
|
);
|
|
|
|
UNLOCK_CHANNEL_OBUFFER(Channel);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelIWrite(
|
|
IN PSAC_CHANNEL Channel,
|
|
IN PCUCHAR Buffer,
|
|
IN ULONG BufferSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the common entry point for all channel iwrite methods.
|
|
The purpose of this entry point is to provide a uniform locking
|
|
scheme for the ibuffer. Channel apps should not call the iwrite method
|
|
directly, but should use this instead.
|
|
|
|
Arguments:
|
|
|
|
Channel - Previously created channel.
|
|
Buffer - The buffer to write
|
|
BufferSize - The size of the buffer to write
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
LOCK_CHANNEL_IBUFFER(Channel);
|
|
|
|
Status = Channel->IWrite(
|
|
Channel,
|
|
Buffer,
|
|
BufferSize
|
|
);
|
|
|
|
UNLOCK_CHANNEL_IBUFFER(Channel);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelIRead(
|
|
IN PSAC_CHANNEL Channel,
|
|
IN PUCHAR Buffer,
|
|
IN ULONG BufferSize,
|
|
OUT PULONG ByteCount
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the common entry point for all channel iread methods.
|
|
The purpose of this entry point is to provide a uniform locking
|
|
scheme for the ibuffer. Channel apps should not call the iread method
|
|
directly, but should use this instead.
|
|
|
|
Arguments:
|
|
|
|
Channel - Previously created channel.
|
|
Buffer - The buffer to read into
|
|
BufferSize - The size of the buffer
|
|
ByteCount - The # of bytes read
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
LOCK_CHANNEL_IBUFFER(Channel);
|
|
|
|
Status = Channel->IRead(
|
|
Channel,
|
|
Buffer,
|
|
BufferSize,
|
|
ByteCount
|
|
);
|
|
|
|
UNLOCK_CHANNEL_IBUFFER(Channel);
|
|
|
|
return Status;
|
|
}
|
|
|
|
WCHAR
|
|
ChannelIReadLast(
|
|
IN PSAC_CHANNEL Channel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the common entry point for all channel ireadlast methods.
|
|
The purpose of this entry point is to provide a uniform locking
|
|
scheme for the ibuffer. Channel apps should not call the ireadlast method
|
|
directly, but should use this instead.
|
|
|
|
Arguments:
|
|
|
|
Channel - Previously created channel.
|
|
|
|
Return Value:
|
|
|
|
The last character, otherwise UNICODE_NULL
|
|
|
|
--*/
|
|
{
|
|
WCHAR wch;
|
|
|
|
LOCK_CHANNEL_IBUFFER(Channel);
|
|
|
|
wch = Channel->IReadLast(Channel);
|
|
|
|
UNLOCK_CHANNEL_IBUFFER(Channel);
|
|
|
|
return wch;
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelIBufferIsFull(
|
|
IN PSAC_CHANNEL Channel,
|
|
OUT BOOLEAN* BufferStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the common entry point for all channel IBufferIsFull methods.
|
|
The purpose of this entry point is to provide a uniform locking
|
|
scheme for the ibuffer. Channel apps should not call the IBufferIsFull method
|
|
directly, but should use this instead.
|
|
|
|
Arguments:
|
|
|
|
Channel - Previously created channel.
|
|
BufferStatus - The query result
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
LOCK_CHANNEL_IBUFFER(Channel);
|
|
|
|
Status = Channel->IBufferIsFull(
|
|
Channel,
|
|
BufferStatus
|
|
);
|
|
|
|
UNLOCK_CHANNEL_IBUFFER(Channel);
|
|
|
|
return Status;
|
|
}
|
|
|
|
ULONG
|
|
ChannelIBufferLength(
|
|
IN PSAC_CHANNEL Channel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the common entry point for all channel IBufferLength methods.
|
|
The purpose of this entry point is to provide a uniform locking
|
|
scheme for the ibuffer. Channel apps should not call the IBufferLength method
|
|
directly, but should use this instead.
|
|
|
|
Arguments:
|
|
|
|
Channel - Previously created channel.
|
|
|
|
Return Value:
|
|
|
|
The last character, otherwise UNICODE_NULL
|
|
|
|
--*/
|
|
{
|
|
ULONG Length;
|
|
|
|
LOCK_CHANNEL_IBUFFER(Channel);
|
|
|
|
Length = Channel->IBufferLength(Channel);
|
|
|
|
UNLOCK_CHANNEL_IBUFFER(Channel);
|
|
|
|
return Length;
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelGetName(
|
|
IN PSAC_CHANNEL Channel,
|
|
OUT PWSTR* Name
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine retrieves the channel's description and stores it
|
|
in a newly allocated buffer
|
|
|
|
Note: the caller is responsible for releasing the memory holding
|
|
the description
|
|
|
|
Arguments:
|
|
|
|
Channel - Previously created channel.
|
|
Name - the retrieved name
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
{
|
|
ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1);
|
|
ASSERT_STATUS(Name, STATUS_INVALID_PARAMETER_2);
|
|
|
|
*Name = ALLOCATE_POOL(SAC_MAX_CHANNEL_NAME_SIZE, GENERAL_POOL_TAG);
|
|
ASSERT_STATUS(*Name, STATUS_NO_MEMORY);
|
|
|
|
LOCK_CHANNEL_ATTRIBUTES(Channel);
|
|
|
|
SAFE_WCSCPY(
|
|
SAC_MAX_CHANNEL_NAME_SIZE,
|
|
*Name,
|
|
Channel->Name
|
|
);
|
|
|
|
UNLOCK_CHANNEL_ATTRIBUTES(Channel);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelSetName(
|
|
IN PSAC_CHANNEL Channel,
|
|
IN PCWSTR Name
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets the channel's name.
|
|
|
|
Arguments:
|
|
|
|
Channel - Previously created channel.
|
|
Name - The new channel name
|
|
|
|
Note: this routine does not check to see if the name is unique
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
{
|
|
ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1);
|
|
ASSERT_STATUS(Name, STATUS_INVALID_PARAMETER_2);
|
|
|
|
LOCK_CHANNEL_ATTRIBUTES(Channel);
|
|
|
|
SAFE_WCSCPY(
|
|
SAC_MAX_CHANNEL_NAME_SIZE,
|
|
Channel->Name,
|
|
Name
|
|
);
|
|
|
|
Channel->Name[SAC_MAX_CHANNEL_NAME_LENGTH] = UNICODE_NULL;
|
|
|
|
UNLOCK_CHANNEL_ATTRIBUTES(Channel);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelGetDescription(
|
|
IN PSAC_CHANNEL Channel,
|
|
OUT PWSTR* Description
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine retrieves the channel's description and stores it
|
|
in a newly allocated buffer
|
|
|
|
Note: the caller is responsible for releasing the memory holding
|
|
the description
|
|
|
|
Arguments:
|
|
|
|
Channel - Previously created channel.
|
|
Description - the retrieved description
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
{
|
|
ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1);
|
|
ASSERT_STATUS(Description, STATUS_INVALID_PARAMETER_2);
|
|
|
|
*Description = ALLOCATE_POOL(SAC_MAX_CHANNEL_DESCRIPTION_SIZE, GENERAL_POOL_TAG);
|
|
ASSERT_STATUS(*Description, STATUS_NO_MEMORY);
|
|
|
|
LOCK_CHANNEL_ATTRIBUTES(Channel);
|
|
|
|
SAFE_WCSCPY(
|
|
SAC_MAX_CHANNEL_DESCRIPTION_SIZE,
|
|
*Description,
|
|
Channel->Description
|
|
);
|
|
|
|
UNLOCK_CHANNEL_ATTRIBUTES(Channel);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelSetDescription(
|
|
IN PSAC_CHANNEL Channel,
|
|
IN PCWSTR Description
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets the channels description.
|
|
|
|
Arguments:
|
|
|
|
Channel - Previously created channel.
|
|
Description - The new description
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
{
|
|
ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1);
|
|
|
|
LOCK_CHANNEL_ATTRIBUTES(Channel);
|
|
|
|
if (Description != NULL) {
|
|
|
|
SAFE_WCSCPY(
|
|
SAC_MAX_CHANNEL_DESCRIPTION_SIZE,
|
|
Channel->Description,
|
|
Description
|
|
);
|
|
|
|
//
|
|
// Force a null termination at the end of the description
|
|
//
|
|
Channel->Description[SAC_MAX_CHANNEL_DESCRIPTION_LENGTH] = UNICODE_NULL;
|
|
|
|
} else {
|
|
|
|
//
|
|
// make the description 0 length
|
|
//
|
|
Channel->Description[0] = UNICODE_NULL;
|
|
|
|
}
|
|
|
|
UNLOCK_CHANNEL_ATTRIBUTES(Channel);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelSetStatus(
|
|
IN PSAC_CHANNEL Channel,
|
|
IN SAC_CHANNEL_STATUS Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets the channels status.
|
|
|
|
Arguments:
|
|
|
|
Channel - Previously created channel.
|
|
Status - The channel's new status
|
|
|
|
Return Value:
|
|
|
|
NTStatus
|
|
|
|
--*/
|
|
{
|
|
ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1);
|
|
|
|
LOCK_CHANNEL_ATTRIBUTES(Channel);
|
|
|
|
Channel->Status = Status;
|
|
|
|
UNLOCK_CHANNEL_ATTRIBUTES(Channel);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelGetStatus(
|
|
IN PSAC_CHANNEL Channel,
|
|
OUT SAC_CHANNEL_STATUS* Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine Gets the channels status.
|
|
|
|
Arguments:
|
|
|
|
Channel - Previously created channel.
|
|
Status - The channel's new status
|
|
|
|
Return Value:
|
|
|
|
NTStatus
|
|
|
|
--*/
|
|
{
|
|
ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1);
|
|
|
|
LOCK_CHANNEL_ATTRIBUTES(Channel);
|
|
|
|
*Status = Channel->Status;
|
|
|
|
UNLOCK_CHANNEL_ATTRIBUTES(Channel);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelSetApplicationType(
|
|
IN PSAC_CHANNEL Channel,
|
|
IN GUID ApplicationType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets the channel's application type.
|
|
|
|
Arguments:
|
|
|
|
Channel - Previously created channel.
|
|
ApplicationType - Application type
|
|
|
|
Return Value:
|
|
|
|
NTStatus
|
|
|
|
--*/
|
|
{
|
|
ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1);
|
|
|
|
LOCK_CHANNEL_ATTRIBUTES(Channel);
|
|
|
|
Channel->ApplicationType = ApplicationType;
|
|
|
|
UNLOCK_CHANNEL_ATTRIBUTES(Channel);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelGetApplicationType(
|
|
IN PSAC_CHANNEL Channel,
|
|
OUT GUID* ApplicationType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine gets the channel's application type.
|
|
|
|
Arguments:
|
|
|
|
Channel - Previously created channel.
|
|
ApplicationType - Application type
|
|
|
|
Return Value:
|
|
|
|
NTStatus
|
|
|
|
--*/
|
|
{
|
|
ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1);
|
|
|
|
LOCK_CHANNEL_ATTRIBUTES(Channel);
|
|
|
|
*ApplicationType = Channel->ApplicationType;
|
|
|
|
UNLOCK_CHANNEL_ATTRIBUTES(Channel);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
#if ENABLE_CHANNEL_LOCKING
|
|
|
|
NTSTATUS
|
|
ChannelSetLockEvent(
|
|
IN PSAC_CHANNEL Channel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the channel lock event
|
|
|
|
Arguments:
|
|
|
|
Channel - The channel to fire the event for
|
|
|
|
Return Value:
|
|
|
|
NTStatus
|
|
|
|
--*/
|
|
{
|
|
|
|
ASSERT_STATUS(Channel->LockEvent, STATUS_UNSUCCESSFUL);
|
|
ASSERT_STATUS(Channel->LockEventObjectBody, STATUS_UNSUCCESSFUL);
|
|
ASSERT_STATUS(Channel->LockEventWaitObjectBody, STATUS_UNSUCCESSFUL);
|
|
|
|
if (Channel->LockEventWaitObjectBody) {
|
|
|
|
//
|
|
// fire the event
|
|
//
|
|
KeSetEvent(
|
|
Channel->LockEventWaitObjectBody,
|
|
EVENT_INCREMENT,
|
|
FALSE
|
|
);
|
|
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
NTSTATUS
|
|
ChannelSetRedrawEvent(
|
|
IN PSAC_CHANNEL Channel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the channel redraw event
|
|
|
|
Arguments:
|
|
|
|
Channel - The channel to fire the event for
|
|
|
|
Return Value:
|
|
|
|
NTStatus
|
|
|
|
--*/
|
|
{
|
|
|
|
ASSERT_STATUS(Channel->RedrawEvent, STATUS_UNSUCCESSFUL);
|
|
ASSERT_STATUS(Channel->RedrawEventObjectBody, STATUS_UNSUCCESSFUL);
|
|
ASSERT_STATUS(Channel->RedrawEventWaitObjectBody, STATUS_UNSUCCESSFUL);
|
|
|
|
if (Channel->RedrawEventWaitObjectBody) {
|
|
|
|
//
|
|
// fire the event
|
|
//
|
|
KeSetEvent(
|
|
Channel->RedrawEventWaitObjectBody,
|
|
EVENT_INCREMENT,
|
|
FALSE
|
|
);
|
|
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelClearRedrawEvent(
|
|
IN PSAC_CHANNEL Channel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Clear the channel redraw event
|
|
|
|
Arguments:
|
|
|
|
Channel - The channel to fire the event for
|
|
|
|
Return Value:
|
|
|
|
NTStatus
|
|
|
|
--*/
|
|
{
|
|
|
|
ASSERT_STATUS(Channel->RedrawEvent, STATUS_UNSUCCESSFUL);
|
|
ASSERT_STATUS(Channel->RedrawEventObjectBody, STATUS_UNSUCCESSFUL);
|
|
ASSERT_STATUS(Channel->RedrawEventWaitObjectBody, STATUS_UNSUCCESSFUL);
|
|
|
|
if (Channel->RedrawEventWaitObjectBody) {
|
|
|
|
//
|
|
// clear the event
|
|
//
|
|
KeClearEvent( Channel->RedrawEventWaitObjectBody );
|
|
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelHasRedrawEvent(
|
|
IN PSAC_CHANNEL Channel,
|
|
OUT PBOOLEAN Present
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines if the channel has the Redraw event present.
|
|
|
|
Arguments:
|
|
|
|
Channel - the channel to query
|
|
|
|
Return Value:
|
|
|
|
TRUE - the channel has the event
|
|
FALSE - Otherwise
|
|
|
|
--*/
|
|
{
|
|
ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1);
|
|
ASSERT_STATUS(Present, STATUS_INVALID_PARAMETER_2);
|
|
|
|
*Present = (ChannelGetFlags(Channel) & SAC_CHANNEL_FLAG_REDRAW_EVENT) ? TRUE : FALSE;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|