reactos/drivers/sac/driver/channel.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;
}