Leaked source code of windows server 2003
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

/*++
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;
}