mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 10:04:49 +00:00
575 lines
16 KiB
C
575 lines
16 KiB
C
/*
|
|
* PROJECT: ReactOS Drivers
|
|
* LICENSE: BSD - See COPYING.ARM in the top level directory
|
|
* FILE: drivers/sac/driver/channel.c
|
|
* PURPOSE: Driver for the Server Administration Console (SAC) for EMS
|
|
* PROGRAMMERS: ReactOS Portable Systems Group
|
|
*/
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
#include "sacdrv.h"
|
|
|
|
/* FUNCTIONS ******************************************************************/
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
ChannelIsValidType(IN SAC_CHANNEL_TYPE ChannelType)
|
|
{
|
|
/* Check if the type is valid */
|
|
return ((ChannelType >= VtUtf8) && (ChannelType <= Raw));
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
ChannelIsEqual(IN PSAC_CHANNEL Channel,
|
|
IN PSAC_CHANNEL_ID ChannelId)
|
|
{
|
|
/* Check if the GUIDs match */
|
|
return IsEqualGUIDAligned(&Channel->ChannelId.ChannelGuid,
|
|
&ChannelId->ChannelGuid);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
ChannelDereferenceHandles(IN PSAC_CHANNEL Channel)
|
|
{
|
|
CHECK_PARAMETER(Channel);
|
|
|
|
/* Clear the data event */
|
|
if (Channel->HasNewDataEvent)
|
|
{
|
|
ChannelUninitializeEvent(Channel,
|
|
HasNewDataEvent,
|
|
SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT);
|
|
}
|
|
|
|
/* Clear the close event */
|
|
if (Channel->CloseEvent)
|
|
{
|
|
ChannelUninitializeEvent(Channel,
|
|
CloseEvent,
|
|
SAC_CHANNEL_FLAG_CLOSE_EVENT);
|
|
}
|
|
|
|
/* Clear the lock event */
|
|
if (Channel->LockEvent)
|
|
{
|
|
ChannelUninitializeEvent(Channel,
|
|
LockEvent,
|
|
SAC_CHANNEL_FLAG_LOCK_EVENT);
|
|
}
|
|
|
|
/* Clear the redraw event */
|
|
if (Channel->RedrawEvent)
|
|
{
|
|
ChannelUninitializeEvent(Channel,
|
|
RedrawEvent,
|
|
SAC_CHANNEL_FLAG_REDRAW_EVENT);
|
|
}
|
|
|
|
/* All done */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
ChannelDestroy(IN PSAC_CHANNEL Channel)
|
|
{
|
|
CHECK_PARAMETER(Channel);
|
|
|
|
/* Same thing as dereferencing all the handles */
|
|
return ChannelDereferenceHandles(Channel);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
ChannelOWrite(IN PSAC_CHANNEL Channel,
|
|
IN PCHAR Buffer,
|
|
IN ULONG BufferSize)
|
|
{
|
|
NTSTATUS Status;
|
|
CHECK_PARAMETER3(BufferSize < SAC_OBUFFER_SIZE);
|
|
|
|
/* While holding the output lock, write to the output buffer */
|
|
ChannelLockOBuffer(Channel);
|
|
Status = Channel->ChannelOutputWrite(Channel, Buffer, BufferSize);
|
|
ChannelUnlockOBuffer(Channel);
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
ChannelOFlush(IN PSAC_CHANNEL Channel)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
/* While holding the output lock, flush to the output buffer */
|
|
ChannelLockOBuffer(Channel);
|
|
Status = Channel->ChannelOutputFlush(Channel);
|
|
ChannelUnlockOBuffer(Channel);
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
ChannelIWrite(IN PSAC_CHANNEL Channel,
|
|
IN PCHAR Buffer,
|
|
IN ULONG BufferSize)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
/* Write into the input buffer while holding the lock */
|
|
ChannelLockIBuffer(Channel);
|
|
Status = Channel->ChannelInputWrite(Channel, Buffer, BufferSize);
|
|
ChannelUnlockIBuffer(Channel);
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
ChannelIRead(IN PSAC_CHANNEL Channel,
|
|
IN PCHAR Buffer,
|
|
IN ULONG BufferSize,
|
|
IN OUT PULONG ResultBufferSize)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
/* Read the input buffer while holding the lock */
|
|
ChannelLockIBuffer(Channel);
|
|
Status = Channel->ChannelInputRead(Channel,
|
|
Buffer,
|
|
BufferSize,
|
|
ResultBufferSize);
|
|
ChannelUnlockIBuffer(Channel);
|
|
return Status;
|
|
}
|
|
|
|
WCHAR
|
|
NTAPI
|
|
ChannelIReadLast(IN PSAC_CHANNEL Channel)
|
|
{
|
|
WCHAR LastChar;
|
|
|
|
/* Read the last character while holding the lock */
|
|
ChannelLockIBuffer(Channel);
|
|
LastChar = Channel->ChannelInputReadLast(Channel);
|
|
ChannelUnlockIBuffer(Channel);
|
|
return LastChar;
|
|
}
|
|
|
|
ULONG
|
|
NTAPI
|
|
ChannelIBufferLength(IN PSAC_CHANNEL Channel)
|
|
{
|
|
ULONG Length;
|
|
|
|
/* Get the input buffer length while holding the lock */
|
|
ChannelLockOBuffer(Channel);
|
|
Length = Channel->ChannelInputBufferLength(Channel);
|
|
ChannelUnlockOBuffer(Channel);
|
|
return Length;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
ChannelSetRedrawEvent(IN PSAC_CHANNEL Channel)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
/* Set the event */
|
|
ChannelSetEvent(Channel, RedrawEvent);
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
ChannelSetLockEvent(IN PSAC_CHANNEL Channel)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
/* Set the event */
|
|
ChannelSetEvent(Channel, LockEvent);
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
ChannelClearRedrawEvent(IN PSAC_CHANNEL Channel)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
/* Clear the event */
|
|
ChannelClearEvent(Channel, RedrawEvent);
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
ChannelHasRedrawEvent(IN PSAC_CHANNEL Channel,
|
|
OUT PBOOLEAN Present)
|
|
{
|
|
CHECK_PARAMETER1(Channel);
|
|
CHECK_PARAMETER2(Present);
|
|
|
|
/* Return if the flag is set */
|
|
*Present = Channel->Flags & SAC_CHANNEL_FLAG_REDRAW_EVENT;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
ChannelGetStatus(IN PSAC_CHANNEL Channel,
|
|
OUT PSAC_CHANNEL_STATUS ChannelStatus)
|
|
{
|
|
CHECK_PARAMETER1(Channel);
|
|
|
|
/* Read the status while holding the attribute lock */
|
|
ChannelLockAttributes(Channel);
|
|
*ChannelStatus = Channel->ChannelStatus;
|
|
ChannelUnlockAttributes(Channel);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
ChannelSetStatus(IN PSAC_CHANNEL Channel,
|
|
IN SAC_CHANNEL_STATUS ChannelStatus)
|
|
{
|
|
CHECK_PARAMETER1(Channel);
|
|
|
|
/* Read the status while holding the attribute lock */
|
|
ChannelLockAttributes(Channel);
|
|
Channel->ChannelStatus = ChannelStatus;
|
|
ChannelUnlockAttributes(Channel);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
ChannelIsActive(IN PSAC_CHANNEL Channel)
|
|
{
|
|
SAC_CHANNEL_STATUS ChannelStatus;
|
|
BOOLEAN IsActive;
|
|
|
|
/* Get the status */
|
|
if (!NT_SUCCESS(ChannelGetStatus(Channel, &ChannelStatus)))
|
|
{
|
|
/* We couldn't even do that, assume it's inactive */
|
|
IsActive = FALSE;
|
|
}
|
|
else
|
|
{
|
|
/* Check if the status shows activity */
|
|
IsActive = (ChannelStatus == Active);
|
|
}
|
|
|
|
/* Return the state */
|
|
return IsActive;
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
ChannelIsClosed(IN PSAC_CHANNEL Channel)
|
|
{
|
|
SAC_CHANNEL_STATUS ChannelStatus;
|
|
BOOLEAN IsClosed;
|
|
|
|
/* Get the status */
|
|
if (!NT_SUCCESS(ChannelGetStatus(Channel, &ChannelStatus)))
|
|
{
|
|
/* We couldn't even do that, assume it's inactive */
|
|
IsClosed = FALSE;
|
|
}
|
|
else
|
|
{
|
|
/* Check if the status shows activity */
|
|
IsClosed = ((ChannelStatus == Inactive) &&
|
|
(Channel->ChannelHasNewOBufferData));
|
|
}
|
|
|
|
/* Return the state */
|
|
return IsClosed;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
ChannelGetName(IN PSAC_CHANNEL Channel,
|
|
OUT PWCHAR *Name)
|
|
{
|
|
CHECK_PARAMETER1(Channel);
|
|
CHECK_PARAMETER2(Name);
|
|
|
|
/* Allocate space to hold the name */
|
|
*Name = SacAllocatePool(sizeof(Channel->NameBuffer), GLOBAL_BLOCK_TAG);
|
|
CHECK_ALLOCATION(*Name);
|
|
|
|
/* Lock the attributes while we copy the name */
|
|
ChannelLockAttributes(Channel);
|
|
|
|
/* Copy the name and null-terminate it */
|
|
ASSERT(((wcslen(Channel->NameBuffer) + 1) * sizeof(WCHAR)) <= ((SAC_CHANNEL_NAME_SIZE + 1) * sizeof(WCHAR)));
|
|
wcsncpy(*Name, Channel->NameBuffer, RTL_NUMBER_OF(Channel->NameBuffer)); // bug
|
|
(*Name)[SAC_CHANNEL_NAME_SIZE] = UNICODE_NULL;
|
|
|
|
/* Release the lock and return */
|
|
ChannelUnlockAttributes(Channel);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
ChannelSetName(IN PSAC_CHANNEL Channel,
|
|
IN PWCHAR Name)
|
|
{
|
|
CHECK_PARAMETER1(Channel);
|
|
CHECK_PARAMETER2(Name);
|
|
|
|
/* Lock the attributes while we copy the name */
|
|
ChannelLockAttributes(Channel);
|
|
|
|
/* Copy the name and null-terminate it */
|
|
ASSERT(((wcslen(Name) + 1) * sizeof(WCHAR)) <= ((SAC_CHANNEL_NAME_SIZE + 1) * sizeof(WCHAR)));
|
|
wcsncpy(Channel->NameBuffer, Name, RTL_NUMBER_OF(Channel->NameBuffer)); // bug
|
|
Channel->NameBuffer[SAC_CHANNEL_NAME_SIZE] = UNICODE_NULL;
|
|
|
|
/* Release the lock and return */
|
|
ChannelUnlockAttributes(Channel);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
ChannelGetDescription(IN PSAC_CHANNEL Channel,
|
|
IN PWCHAR* Description)
|
|
{
|
|
CHECK_PARAMETER1(Channel);
|
|
CHECK_PARAMETER2(Description);
|
|
|
|
/* Allocate space to hold the description */
|
|
*Description = SacAllocatePool(sizeof(Channel->DescriptionBuffer), GLOBAL_BLOCK_TAG);
|
|
CHECK_ALLOCATION(*Description);
|
|
|
|
/* Lock the attributes while we copy the name */
|
|
ChannelLockAttributes(Channel);
|
|
|
|
/* Copy the name and null-terminate it */
|
|
ASSERT(((wcslen(Channel->DescriptionBuffer) + 1) * sizeof(WCHAR)) <= ((SAC_CHANNEL_DESCRIPTION_SIZE + 1) * sizeof(WCHAR)));
|
|
wcsncpy(*Description, Channel->DescriptionBuffer, RTL_NUMBER_OF(Channel->DescriptionBuffer)); // bug
|
|
(*Description)[SAC_CHANNEL_DESCRIPTION_SIZE] = UNICODE_NULL;
|
|
|
|
/* Release the lock and return */
|
|
ChannelUnlockAttributes(Channel);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
ChannelSetDescription(IN PSAC_CHANNEL Channel,
|
|
IN PWCHAR Description)
|
|
{
|
|
CHECK_PARAMETER1(Channel);
|
|
CHECK_PARAMETER2(Description);
|
|
|
|
/* Lock the attributes while we copy the name */
|
|
ChannelLockAttributes(Channel);
|
|
|
|
/* Copy the name and null-terminate it */
|
|
ASSERT(((wcslen(Description) + 1) * sizeof(WCHAR)) <= ((SAC_CHANNEL_NAME_SIZE + 1) * sizeof(WCHAR)));
|
|
wcsncpy(Channel->DescriptionBuffer, Description, RTL_NUMBER_OF(Channel->DescriptionBuffer)); // bug
|
|
Channel->DescriptionBuffer[SAC_CHANNEL_DESCRIPTION_SIZE] = UNICODE_NULL;
|
|
|
|
/* Release the lock and return */
|
|
ChannelUnlockAttributes(Channel);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
ChannelGetApplicationType(IN PSAC_CHANNEL Channel,
|
|
OUT PGUID ApplicationType)
|
|
{
|
|
CHECK_PARAMETER1(Channel);
|
|
|
|
/* Read the application type GUID */
|
|
ChannelLockAttributes(Channel);
|
|
*ApplicationType = Channel->ApplicationType;
|
|
ChannelUnlockAttributes(Channel);
|
|
|
|
/* Always return success */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
ChannelInitializeVTable(IN PSAC_CHANNEL Channel)
|
|
{
|
|
/* What kind of channel is this? */
|
|
switch (Channel->ChannelType)
|
|
{
|
|
case VtUtf8:
|
|
/* Setup the calls for a VT-UTF8 channel */
|
|
Channel->ChannelCreate = VTUTF8ChannelCreate;
|
|
Channel->ChannelDestroy = VTUTF8ChannelDestroy;
|
|
Channel->ChannelOutputFlush = VTUTF8ChannelOFlush;
|
|
Channel->ChannelOutputEcho = VTUTF8ChannelOEcho;
|
|
Channel->ChannelOutputWrite = VTUTF8ChannelOWrite;
|
|
Channel->ChannelOutputRead = VTUTF8ChannelORead;
|
|
Channel->ChannelInputWrite = VTUTF8ChannelIWrite;
|
|
Channel->ChannelInputRead = VTUTF8ChannelIRead;
|
|
Channel->ChannelInputReadLast = VTUTF8ChannelIReadLast;
|
|
Channel->ChannelInputBufferIsFull = VTUTF8ChannelIBufferIsFull;
|
|
Channel->ChannelInputBufferLength = VTUTF8ChannelIBufferLength;
|
|
break;
|
|
|
|
case Cmd:
|
|
/* FIXME: TODO */
|
|
ASSERT(FALSE);
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
case Raw:
|
|
|
|
/* Setup the calls for a raw channel */
|
|
Channel->ChannelCreate = RawChannelCreate;
|
|
Channel->ChannelDestroy = RawChannelDestroy;
|
|
Channel->ChannelOutputFlush = RawChannelOFlush;
|
|
Channel->ChannelOutputEcho = RawChannelOEcho;
|
|
Channel->ChannelOutputWrite = RawChannelOWrite;
|
|
Channel->ChannelOutputRead = RawChannelORead;
|
|
Channel->ChannelInputWrite = RawChannelIWrite;
|
|
Channel->ChannelInputRead = RawChannelIRead;
|
|
Channel->ChannelInputReadLast = RawChannelIReadLast;
|
|
Channel->ChannelInputBufferIsFull = RawChannelIBufferIsFull;
|
|
Channel->ChannelInputBufferLength = RawChannelIBufferLength;
|
|
break;
|
|
|
|
default:
|
|
/* Unsupported channel type */
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* If we got here, the channel was supported */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
ChannelCreate(IN PSAC_CHANNEL Channel,
|
|
IN PSAC_CHANNEL_ATTRIBUTES Attributes,
|
|
IN SAC_CHANNEL_ID ChannelId)
|
|
{
|
|
NTSTATUS Status;
|
|
CHECK_PARAMETER1(Channel);
|
|
CHECK_PARAMETER2(Attributes);
|
|
|
|
/* If a close event is being passed in, it must exist, and vice-versa */
|
|
if (Attributes->Flag & SAC_CHANNEL_FLAG_CLOSE_EVENT)
|
|
{
|
|
CHECK_PARAMETER(Attributes->CloseEvent != NULL);
|
|
}
|
|
else
|
|
{
|
|
CHECK_PARAMETER(Attributes->CloseEvent == NULL);
|
|
}
|
|
|
|
/* If a new data event is being passed in, it must exist, and vice-versa */
|
|
if (Attributes->Flag & SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT)
|
|
{
|
|
CHECK_PARAMETER(Attributes->HasNewDataEvent != NULL);
|
|
}
|
|
else
|
|
{
|
|
CHECK_PARAMETER(Attributes->HasNewDataEvent == NULL);
|
|
}
|
|
|
|
/* If a lock event is being passed in, it must exist, and vice-versa */
|
|
if (Attributes->Flag & SAC_CHANNEL_FLAG_LOCK_EVENT)
|
|
{
|
|
CHECK_PARAMETER(Attributes->LockEvent != NULL);
|
|
}
|
|
else
|
|
{
|
|
CHECK_PARAMETER(Attributes->LockEvent == NULL);
|
|
}
|
|
|
|
/* If a redraw event is being passed in, it must exist, and vice-versa */
|
|
if (Attributes->Flag & SAC_CHANNEL_FLAG_REDRAW_EVENT)
|
|
{
|
|
CHECK_PARAMETER(Attributes->RedrawEvent != NULL);
|
|
}
|
|
else
|
|
{
|
|
CHECK_PARAMETER(Attributes->RedrawEvent == NULL);
|
|
}
|
|
|
|
/* Initialize the channel structure */
|
|
RtlZeroMemory(Channel, sizeof(SAC_CHANNEL));
|
|
Channel->ChannelId = ChannelId;
|
|
Channel->ChannelType = Attributes->ChannelType;
|
|
Channel->Flags = Attributes->Flag;
|
|
if (Attributes->Flag & SAC_CHANNEL_FLAG_APPLICATION)
|
|
{
|
|
Channel->ApplicationType = Attributes->ChannelId;
|
|
}
|
|
|
|
/* Initialize all the locks and events */
|
|
SacInitializeLock(&Channel->ChannelAttributeLock);
|
|
SacInitializeLock(&Channel->ChannelOBufferLock);
|
|
SacInitializeLock(&Channel->ChannelIBufferLock);
|
|
ChannelInitializeEvent(Channel, Attributes, CloseEvent);
|
|
ChannelInitializeEvent(Channel, Attributes, HasNewDataEvent);
|
|
ChannelInitializeEvent(Channel, Attributes, LockEvent);
|
|
ChannelInitializeEvent(Channel, Attributes, RedrawEvent);
|
|
|
|
/* Set the name and description */
|
|
ChannelSetName(Channel, Attributes->NameBuffer);
|
|
ChannelSetDescription(Channel, Attributes->DescriptionBuffer);
|
|
|
|
/* Initialize the function table for the type of channel this is */
|
|
Status = ChannelInitializeVTable(Channel);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* This is critical */
|
|
SAC_DBG(SAC_DBG_INIT, "SAC Create Channel :: Failed to initialize vtable\n");
|
|
goto FailChannel;
|
|
}
|
|
|
|
/* Now call the channel specific type constructor */
|
|
Status = Channel->ChannelCreate(Channel);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* This is critical */
|
|
SAC_DBG(SAC_DBG_INIT, "SAC Create Channel :: Failed channel specific initialization\n");
|
|
goto FailChannel;
|
|
}
|
|
|
|
/* Finally, mark the channel as active */
|
|
ChannelSetStatus(Channel, Active);
|
|
return STATUS_SUCCESS;
|
|
|
|
FailChannel:
|
|
/* Destroy the channel and return the failure code */
|
|
Channel->ChannelDestroy(Channel);
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
ChannelClose(IN PSAC_CHANNEL Channel)
|
|
{
|
|
NTSTATUS Status;
|
|
CHECK_PARAMETER(Channel);
|
|
|
|
/* Set the channel inactive */
|
|
ChannelSetStatus(Channel, Inactive);
|
|
|
|
/* Set the close event */
|
|
if (Channel->Flags & SAC_CHANNEL_FLAG_CLOSE_EVENT)
|
|
{
|
|
ChannelSetEvent(Channel, CloseEvent);
|
|
}
|
|
|
|
/* Close all the handles */
|
|
Status = ChannelDereferenceHandles(Channel);
|
|
return Status;
|
|
}
|