|
|
/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
sacapi.c
Abstract:
This is the C library used to interface to SAC driver.
Author:
Brian Guarraci (briangu)
Revision History:
--*/
#include "sacapip.h"
#include <sacapi.h>
#include <ntddsac.h>
#if DBG
//
// Counter to keep track of how many driver handles have been
// requested and released.
//
static ULONG DriverHandleRefCount = 0; #endif
//
// Memory management routine aliases
//
#define SAC_API_ALLOCATE_MEMORY(s) LocalAlloc(LPTR, (s))
#define SAC_API_FREE_MEMORY(p) LocalFree(p)
//
// enhanced assertion:
//
// First assert the condition,
// if ASSERTs are turned off,
// we bail out of the function with a status
//
#define SAC_API_ASSERT(c,s) \
ASSERT(c); \ if (!(c)) { \ Status = s; \ __leave; \ }
typedef GUID* PGUID;
BOOL SacHandleOpen( OUT HANDLE* SacHandle ) /*++
Routine Description:
Initialize a handle to the SAC driver
Arguments:
SacHandle - A pointer to the SAC Handle Return Value:
Status
TRUE --> SacHandle is valid --*/ { BOOL Status;
Status = TRUE;
__try { SAC_API_ASSERT(SacHandle, FALSE);
//
// Open the SAC
//
// SECURITY:
//
// this handle cannot be inherited
//
*SacHandle = CreateFile( L"\\\\.\\SAC", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL ); if (*SacHandle == INVALID_HANDLE_VALUE) { Status = FALSE; } #if DBG
else { InterlockedIncrement((volatile long *)&DriverHandleRefCount); } #endif
} __except(EXCEPTION_EXECUTE_HANDLER) { ASSERT(0); Status = FALSE; }
return Status; }
BOOL SacHandleClose( IN OUT HANDLE* SacHandle ) /*++
Routine Description:
Close the handle to the SAC driver
Arguments:
SacHandle - A handle to the SAC driver
Return Value:
Status TRUE --> SacHandle is now invalid (NULL) --*/ { BOOL Status;
//
// default: we succeeded to close the handle
//
Status = TRUE; __try { SAC_API_ASSERT(SacHandle, FALSE); SAC_API_ASSERT(*SacHandle != INVALID_HANDLE_VALUE, FALSE); //
// close the handle to the SAC driver
//
Status = CloseHandle(*SacHandle);
if (Status == TRUE) { //
// NULL the SAC driver handle
//
*SacHandle = INVALID_HANDLE_VALUE; #if DBG
InterlockedDecrement((volatile long *)&DriverHandleRefCount); #endif
} } __except(EXCEPTION_EXECUTE_HANDLER) { ASSERT(0); Status = FALSE; } return Status; }
BOOL SacChannelOpen( OUT PSAC_CHANNEL_HANDLE SacChannelHandle, IN PSAC_CHANNEL_OPEN_ATTRIBUTES SacChannelAttributes ) /*++
Routine Description:
Open a SAC channel of the specified name
Arguments:
SacChannelHandle - The handle to the newly created channel SacChannelAttributes - The attributes describing the new channel Note: The SacChannelDescription parameter is optional. If SacChannelDescription != NULL, then the Channel description will be assigned the Unicode string pointed to by SacChannelDescription. If SacChannelDescription == NULL, then the Channel description will be null upon creation. Return Value:
Status
TRUE --> pHandle is valid --*/
{ BOOL Status; ULONG OpenChannelCmdSize; PSAC_CMD_OPEN_CHANNEL OpenChannelCmd; SAC_RSP_OPEN_CHANNEL OpenChannelRsp; DWORD Feedback; HANDLE DriverHandle;
//
// default
//
Status = FALSE; OpenChannelCmdSize = 0; OpenChannelCmd = NULL; DriverHandle = INVALID_HANDLE_VALUE;
__try { SAC_API_ASSERT(SacChannelHandle, FALSE); SAC_API_ASSERT(SacChannelAttributes, FALSE);
//
// Get a handle to the driver and store it in the
// Channel handle. This way, the api user doesn't have
// explicitly open/close the driver handle.
//
Status = SacHandleOpen(&DriverHandle);
if ((Status != TRUE) || (DriverHandle == INVALID_HANDLE_VALUE)) { Status = FALSE; __leave; }
SAC_API_ASSERT(Status == TRUE, FALSE); SAC_API_ASSERT(DriverHandle != INVALID_HANDLE_VALUE, FALSE);
//
// Verify that if the user wants to use the CLOSE_EVENT, we received one to use
//
SAC_API_ASSERT( ((SacChannelAttributes->Flags & SAC_CHANNEL_FLAG_CLOSE_EVENT) && SacChannelAttributes->CloseEvent) || (!(SacChannelAttributes->Flags & SAC_CHANNEL_FLAG_CLOSE_EVENT) && !SacChannelAttributes->CloseEvent), FALSE );
//
// Verify that if the user wants to use the HAS_NEW_DATA_EVENT, we received one to use
//
SAC_API_ASSERT( ((SacChannelAttributes->Flags & SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT) && SacChannelAttributes->HasNewDataEvent) || (!(SacChannelAttributes->Flags & SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT) && !SacChannelAttributes->HasNewDataEvent), FALSE );
#if ENABLE_CHANNEL_LOCKING
//
// Verify that if the user wants to use the LOCK_EVENT, we received one to use
//
SAC_API_ASSERT( ((SacChannelAttributes->Flags & SAC_CHANNEL_FLAG_LOCK_EVENT) && SacChannelAttributes->LockEvent) || (!(SacChannelAttributes->Flags & SAC_CHANNEL_FLAG_LOCK_EVENT) && !SacChannelAttributes->LockEvent), FALSE ); #endif
//
// Verify that if the user wants to use the REDRAW_EVENT, we received one to use
//
SAC_API_ASSERT( ((SacChannelAttributes->Flags & SAC_CHANNEL_FLAG_REDRAW_EVENT) && SacChannelAttributes->RedrawEvent) || (!(SacChannelAttributes->Flags & SAC_CHANNEL_FLAG_REDRAW_EVENT) && !SacChannelAttributes->RedrawEvent), FALSE );
//
// If the channel type isn't cmd,
// then make sure they sent us a name.
//
if (SacChannelAttributes->Type != ChannelTypeCmd) {
SAC_API_ASSERT(SacChannelAttributes->Name, FALSE);
}
__try {
//
// create and initialize the Open Channel message structure
//
OpenChannelCmdSize = sizeof(SAC_CMD_OPEN_CHANNEL); OpenChannelCmd = (PSAC_CMD_OPEN_CHANNEL)SAC_API_ALLOCATE_MEMORY(OpenChannelCmdSize); SAC_API_ASSERT(OpenChannelCmd, FALSE);
//
// Populate the new channel attributes
//
OpenChannelCmd->Attributes = *SacChannelAttributes;
//
// If the channel type isn't cmd,
// then make sure they sent us a name.
//
if (SacChannelAttributes->Type == ChannelTypeCmd) {
//
// force the name and description to be empty
//
OpenChannelCmd->Attributes.Name[0] = UNICODE_NULL; OpenChannelCmd->Attributes.Description[0] = UNICODE_NULL;
}
//
// Send down an IOCTL for opening a channel
//
Status = DeviceIoControl( DriverHandle, IOCTL_SAC_OPEN_CHANNEL, OpenChannelCmd, OpenChannelCmdSize, &OpenChannelRsp, sizeof(SAC_RSP_OPEN_CHANNEL), &Feedback, 0 );
//
// if the channel was not successfully created, NULL
// the channel handle
//
if (Status == FALSE) {
__leave;
}
//
// the new channel was created, so pass back the handle to it
//
SacChannelHandle->DriverHandle = DriverHandle; SacChannelHandle->ChannelHandle = OpenChannelRsp.Handle.ChannelHandle;
} __except(EXCEPTION_EXECUTE_HANDLER) { Status = FALSE; } } __finally { if (OpenChannelCmd) {
//
// free the Open Channel message structure
//
SAC_API_FREE_MEMORY(OpenChannelCmd);
} if (Status == FALSE) { if (DriverHandle != INVALID_HANDLE_VALUE) { //
// Release the driver handle
//
SacHandleClose(&DriverHandle); //
// NULL the sac channel handle
//
RtlZeroMemory(SacChannelHandle, sizeof(SAC_CHANNEL_HANDLE)); } } }
return Status; }
BOOL SacChannelClose( IN OUT PSAC_CHANNEL_HANDLE SacChannelHandle )
/*++
Routine Description:
Close the specified SAC channel NOTE: the channel pointer is made NULL under all conditions
Arguments:
SacChannelHandle - Channel to be closed
Return Value:
Status TRUE --> the channel was closed
--*/
{ BOOL Status; SAC_CMD_CLOSE_CHANNEL CloseChannelCmd; DWORD Feedback;
__try { if (!SacChannelHandle || (SacChannelHandle == INVALID_HANDLE_VALUE) || (SacChannelHandle->DriverHandle == INVALID_HANDLE_VALUE) || !SacChannelHandle->DriverHandle) { Status = FALSE; __leave; }
SAC_API_ASSERT(SacChannelHandle, FALSE); SAC_API_ASSERT(SacChannelHandle->DriverHandle != INVALID_HANDLE_VALUE, FALSE); //
// initialize the Close Channel message
//
RtlZeroMemory(&CloseChannelCmd, sizeof(SAC_CMD_CLOSE_CHANNEL));
CloseChannelCmd.Handle.ChannelHandle = SacChannelHandle->ChannelHandle;
//
// Send down the IOCTL for closing the channel
//
Status = DeviceIoControl( SacChannelHandle->DriverHandle, IOCTL_SAC_CLOSE_CHANNEL, &CloseChannelCmd, sizeof(SAC_CMD_CLOSE_CHANNEL), NULL, 0, &Feedback, 0 );
//
// Close the handle to the driver
//
SacHandleClose(&SacChannelHandle->DriverHandle); //
// The channel handle is no longer valid, so NULL it
//
RtlZeroMemory(&SacChannelHandle->ChannelHandle, sizeof(GUID));
} __except(EXCEPTION_EXECUTE_HANDLER) { Status = FALSE; }
return Status; }
BOOL SacChannelWrite( IN SAC_CHANNEL_HANDLE SacChannelHandle, IN PCBYTE Buffer, IN ULONG BufferSize )
/*++
Routine Description:
Write the given buffer to the specified SAC Channel
Arguments:
SacChannelHandle - The channel to write the buffer to Buffer - data buffer BufferSize - size of the buffer
Return Value:
Status
TRUE --> the buffer was sent
--*/ { BOOL Status; ULONG WriteChannelCmdSize; PSAC_CMD_WRITE_CHANNEL WriteChannelCmd; DWORD Feedback;
//
// Default
//
Status = FALSE; WriteChannelCmdSize = 0; WriteChannelCmd = NULL;
__try {
SAC_API_ASSERT(SacChannelHandle.DriverHandle, FALSE); SAC_API_ASSERT(SacChannelHandle.DriverHandle != INVALID_HANDLE_VALUE, FALSE); SAC_API_ASSERT(Buffer, FALSE); SAC_API_ASSERT(BufferSize > 0, FALSE);
//
// create and initialize the Open Channel message structure
//
WriteChannelCmdSize = sizeof(SAC_CMD_WRITE_CHANNEL) + BufferSize; WriteChannelCmd = (PSAC_CMD_WRITE_CHANNEL)SAC_API_ALLOCATE_MEMORY(WriteChannelCmdSize); SAC_API_ASSERT(WriteChannelCmd, FALSE);
__try { //
// Indicate which channel this command is for
//
WriteChannelCmd->Handle.ChannelHandle = SacChannelHandle.ChannelHandle;
//
// Set the length of the string to send
//
// Note: Size does not include the terminating NULL,
// becase we don't want to send that.
//
WriteChannelCmd->Size = BufferSize;
//
// Set the buffer to be written
//
RtlCopyMemory( &(WriteChannelCmd->Buffer), Buffer, BufferSize );
//
// Send down the IOCTL for writing the message
//
Status = DeviceIoControl( SacChannelHandle.DriverHandle, IOCTL_SAC_WRITE_CHANNEL, WriteChannelCmd, WriteChannelCmdSize, NULL, 0, &Feedback, 0 ); } __except(EXCEPTION_EXECUTE_HANDLER) { Status = FALSE; } } __finally {
//
// if the cmd memory was allocated,
// then release it
//
if (WriteChannelCmd) { SAC_API_FREE_MEMORY(WriteChannelCmd); }
}
return Status; }
BOOL SacChannelRawWrite( IN SAC_CHANNEL_HANDLE SacChannelHandle, IN PCBYTE Buffer, IN ULONG BufferSize )
/*++
Routine Description:
Write the given buffer to the specified SAC Channel
Arguments:
SacChannelHandle - The channel to write the buffer to Buffer - data buffer BufferSize - size of the buffer
Return Value:
Status
TRUE --> the buffer was sent
--*/ { //
// relay the write to the actual write routine
//
return SacChannelWrite( SacChannelHandle, Buffer, BufferSize );
}
BOOL SacChannelVTUTF8WriteString( IN SAC_CHANNEL_HANDLE SacChannelHandle, IN PCWSTR String )
/*++
Routine Description:
This routine writes a null-terminated Unicode String to the specified Channel.
Arguments:
SacChannelHandle - The channel to write the buffer to String - A null-terminated Unicode string
Return Value:
Status
TRUE --> the buffer was sent
--*/ { BOOL Status; ULONG BufferSize;
__try { //
// Treating the String as a data buffer, we calculate it's size
// not including the null termination
//
BufferSize = (ULONG)(wcslen(String) * sizeof(WCHAR)); SAC_API_ASSERT(BufferSize > 0, FALSE);
//
// Write the data to the channel
//
Status = SacChannelWrite( SacChannelHandle, (PCBYTE)String, BufferSize ); } __except(EXCEPTION_EXECUTE_HANDLER) { Status = FALSE; }
return Status;
}
BOOL SacChannelVTUTF8Write( IN SAC_CHANNEL_HANDLE SacChannelHandle, IN PCWCHAR Buffer, IN ULONG BufferSize )
/*++
Routine Description:
This routines writes an array of WCHAR to the VTUTF8 channel specified.
Arguments:
SacChannelHandle - The channel to write the buffer to Buffer - data buffer BufferSize - size of the buffer
Note: Buffer is not null-terminated BufferSize should not count a null-termination. Return Value:
Status
TRUE --> the buffer was sent
--*/ { //
// relay the write to the actual write routine
//
return SacChannelWrite( SacChannelHandle, (PCBYTE)Buffer, BufferSize ); }
BOOL SacChannelHasNewData( IN SAC_CHANNEL_HANDLE SacChannelHandle, OUT PBOOL InputWaiting )
/*++
Routine Description:
This routine checks to see if there is any waiting input for the channel specified by the handle
Arguments:
SacChannelHandle - the channel to write the string to InputWaiting - the input buffer status Return Value:
Status
TRUE --> the buffer status was retrieved
--*/
{ BOOL Status; SAC_CMD_POLL_CHANNEL PollChannelCmd; SAC_RSP_POLL_CHANNEL PollChannelRsp; DWORD Feedback;
__try {
SAC_API_ASSERT(SacChannelHandle.DriverHandle, FALSE); SAC_API_ASSERT(SacChannelHandle.DriverHandle != INVALID_HANDLE_VALUE, FALSE);
//
// Initialize and populate the poll command structure
//
RtlZeroMemory(&PollChannelCmd, sizeof(SAC_CMD_POLL_CHANNEL));
PollChannelCmd.Handle.ChannelHandle = SacChannelHandle.ChannelHandle;
//
// Send down the IOCTL to poll for new input
//
Status = DeviceIoControl( SacChannelHandle.DriverHandle, IOCTL_SAC_POLL_CHANNEL, &PollChannelCmd, sizeof(SAC_CMD_POLL_CHANNEL), &PollChannelRsp, sizeof(SAC_RSP_POLL_CHANNEL), &Feedback, 0 );
if (Status) { *InputWaiting = PollChannelRsp.InputWaiting; } } __except(EXCEPTION_EXECUTE_HANDLER) { Status = FALSE; }
return Status;
}
BOOL SacChannelRead( IN SAC_CHANNEL_HANDLE SacChannelHandle, OUT PBYTE Buffer, IN ULONG BufferSize, OUT PULONG ByteCount )
/*++
Routine Description:
This routine reads data from the channel specified.
Arguments:
SacChannelHandle - the channel to read from Buffer - destination buffer BufferSize - size of the destination buffer (bytes) ByteCount - the actual # of byte read Return Value:
Status
TRUE --> the buffer was read
--*/
{ BOOL Status; SAC_CMD_READ_CHANNEL ReadChannelCmd; PSAC_RSP_READ_CHANNEL ReadChannelRsp;
__try { SAC_API_ASSERT(SacChannelHandle.DriverHandle, FALSE); SAC_API_ASSERT(SacChannelHandle.DriverHandle != INVALID_HANDLE_VALUE, FALSE); SAC_API_ASSERT(Buffer, FALSE); SAC_API_ASSERT(ByteCount, FALSE);
//
// Populate the read channel cmd
//
RtlZeroMemory(&ReadChannelCmd, sizeof(SAC_CMD_READ_CHANNEL));
ReadChannelCmd.Handle.ChannelHandle = SacChannelHandle.ChannelHandle; ReadChannelRsp = (PSAC_RSP_READ_CHANNEL)Buffer;
//
// Send down the IOCTL to read input
//
Status = DeviceIoControl( SacChannelHandle.DriverHandle, IOCTL_SAC_READ_CHANNEL, &ReadChannelCmd, sizeof(SAC_CMD_READ_CHANNEL), ReadChannelRsp, BufferSize, ByteCount, 0 ); } __except(EXCEPTION_EXECUTE_HANDLER) { Status = FALSE; }
return Status;
}
BOOL SacChannelVTUTF8Read( IN SAC_CHANNEL_HANDLE SacChannelHandle, OUT PWSTR Buffer, IN ULONG BufferSize, OUT PULONG ByteCount )
/*++
Routine Description:
This routine reads data from the channel specified.
Arguments:
SacChannelHandle - the channel to read from Buffer - destination buffer BufferSize - size of the destination buffer (bytes) ByteCount - the actual # of byte read Note: the Buffer upon return is NOT null terminated Return Value:
Status
TRUE --> the buffer was read
--*/
{
return SacChannelRead( SacChannelHandle, (PBYTE)Buffer, BufferSize, ByteCount );
}
BOOL SacChannelRawRead( IN SAC_CHANNEL_HANDLE SacChannelHandle, OUT PBYTE Buffer, IN ULONG BufferSize, OUT PULONG ByteCount )
/*++
Routine Description:
This routine reads data from the channel specified.
Arguments:
SacChannelHandle - the channel to read from Buffer - destination buffer BufferSize - size of the destination buffer (bytes) ByteCount - the actual # of byte read Return Value:
Status
TRUE --> the buffer was read
--*/
{ return SacChannelRead( SacChannelHandle, Buffer, BufferSize, ByteCount );
}
BOOL SacRegisterCmdEvent( OUT HANDLE *pDriverHandle, IN HANDLE RequestSacCmdEvent, IN HANDLE RequestSacCmdSuccessEvent, IN HANDLE RequestSacCmdFailureEvent )
/*++
Routine Description:
This routine configures the SAC driver with the event handlers and needed to implement the ability to launch cmd consoles via a user-mode service app.
Note: Only one registration can exist at a time in the SAC driver.
Arguments:
pDriverHandle - on success, contains the driver handle used to register RequestSacCmdEvent - the event triggered when the SAC wants to launch a cmd console RequestSacCmdSuccessEvent - the event triggered when the cmd console has successfully launched RequestSacCmdFailureEvent - the event triggered when the cmd console has failed to launch Return Value:
Status
TRUE --> the cmd event was registered with the SAC driver
--*/
{ BOOL Status; DWORD Feedback; SAC_CMD_SETUP_CMD_EVENT SacCmdEvent; HANDLE DriverHandle;
//
// default
//
*pDriverHandle = INVALID_HANDLE_VALUE;
__try { SAC_API_ASSERT(pDriverHandle != NULL, FALSE); SAC_API_ASSERT(RequestSacCmdEvent, FALSE); SAC_API_ASSERT(RequestSacCmdSuccessEvent, FALSE); SAC_API_ASSERT(RequestSacCmdFailureEvent, FALSE);
//
// Get a handle to the driver. This way, the api user doesn't have
// explicitly open/close the driver handle.
//
Status = SacHandleOpen(&DriverHandle);
if ((Status != TRUE) || (DriverHandle == INVALID_HANDLE_VALUE)) { Status = FALSE; __leave; } SAC_API_ASSERT(Status == TRUE, FALSE); SAC_API_ASSERT(DriverHandle != INVALID_HANDLE_VALUE, FALSE); //
// Initialize the our SAC Cmd Info
//
SacCmdEvent.RequestSacCmdEvent = RequestSacCmdEvent; SacCmdEvent.RequestSacCmdSuccessEvent = RequestSacCmdSuccessEvent; SacCmdEvent.RequestSacCmdFailureEvent = RequestSacCmdFailureEvent;
//
// Send down the IOCTL for setting up the SAC Cmd launch event
//
Status = DeviceIoControl( DriverHandle, IOCTL_SAC_REGISTER_CMD_EVENT, &SacCmdEvent, sizeof(SAC_CMD_SETUP_CMD_EVENT), NULL, 0, &Feedback, 0 );
//
// if we were successful,
// then keep the driver handle
//
if (Status) { *pDriverHandle = DriverHandle; } else {
//
// Close the driver handle
//
SacHandleClose(&DriverHandle);
}
} __except(EXCEPTION_EXECUTE_HANDLER) { Status = FALSE; }
return Status; }
BOOL SacUnRegisterCmdEvent( IN OUT HANDLE *pDriverHandle )
/*++
Routine Description:
This routine unregisters the event information required to launch cmd consoles via a user-mode service app.
Arguments:
pDriverHandle - on entry, contains the driver handle that was used to register the cmd event info on success, contains INVALID_HANDLE_VALUE Return Value:
Status
TRUE --> the cmd event was unregistered with the SAC driver
--*/
{ BOOL Status; DWORD Feedback;
//
// default
//
Status = FALSE;
__try {
SAC_API_ASSERT(*pDriverHandle != INVALID_HANDLE_VALUE, FALSE); //
// Send down the IOCTL for unregistering the SAC Cmd launch event
//
Status = DeviceIoControl( *pDriverHandle, IOCTL_SAC_UNREGISTER_CMD_EVENT, NULL, 0, NULL, 0, &Feedback, 0 ); //
// Close the driver handle
//
SacHandleClose(pDriverHandle);
} __except(EXCEPTION_EXECUTE_HANDLER) { Status = FALSE; }
return Status; }
|