465 lines
14 KiB
C++
465 lines
14 KiB
C++
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Copyright (c) 2001 Microsoft Corporation
|
||
|
//
|
||
|
// Module Name:
|
||
|
// utils.cpp
|
||
|
//
|
||
|
// Abstract:
|
||
|
// This module contains general utility functions.
|
||
|
//
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
|
||
|
|
||
|
// ---------------------------------------------------------
|
||
|
//
|
||
|
// Function: TdiLibStatusMessage
|
||
|
//
|
||
|
// Arguments: ulGeneralStatus -- NTSTATUS value to search
|
||
|
//
|
||
|
// Returns: String with message to print
|
||
|
//
|
||
|
// Descript: This function finds and returns a string corresponding
|
||
|
// to the status passed in..
|
||
|
//
|
||
|
// ----------------------------------------------------------
|
||
|
|
||
|
|
||
|
TCHAR *
|
||
|
TdiLibStatusMessage(NTSTATUS lStatus)
|
||
|
|
||
|
{
|
||
|
static TCHAR UnknownMess[64];
|
||
|
TCHAR *Message;
|
||
|
|
||
|
switch(lStatus)
|
||
|
{
|
||
|
case STATUS_SUCCESS:
|
||
|
Message = TEXT("STATUS_SUCCESS");
|
||
|
break;
|
||
|
case STATUS_UNSUCCESSFUL:
|
||
|
Message = TEXT("STATUS_UNSUCCESSFUL");
|
||
|
break;
|
||
|
case STATUS_NOT_IMPLEMENTED:
|
||
|
Message = TEXT("STATUS_NOT_IMPLEMENTED");
|
||
|
break;
|
||
|
case STATUS_INVALID_HANDLE:
|
||
|
Message = TEXT("STATUS_INVALID_HANDLE");
|
||
|
break;
|
||
|
case STATUS_INVALID_PARAMETER:
|
||
|
Message = TEXT("STATUS_INVALID_PARAMETER");
|
||
|
break;
|
||
|
case STATUS_INVALID_DEVICE_REQUEST:
|
||
|
Message = TEXT("STATUS_INVALID_DEVICE_REQUEST");
|
||
|
break;
|
||
|
case STATUS_INSUFFICIENT_RESOURCES:
|
||
|
Message = TEXT("STATUS_INSUFFICIENT_RESOURCES");
|
||
|
break;
|
||
|
case STATUS_NOT_SUPPORTED:
|
||
|
Message = TEXT("STATUS_NOT_SUPPORTED");
|
||
|
break;
|
||
|
case STATUS_BUFFER_OVERFLOW:
|
||
|
Message = TEXT("STATUS_BUFFER_OVERFLOW");
|
||
|
break;
|
||
|
case STATUS_PENDING:
|
||
|
Message = TEXT("STATUS_PENDING");
|
||
|
break;
|
||
|
case STATUS_CONNECTION_REFUSED:
|
||
|
Message = TEXT("STATUS_CONNECTION_REFUSED");
|
||
|
break;
|
||
|
case STATUS_GRACEFUL_DISCONNECT:
|
||
|
Message = TEXT("STATUS_GRACEFUL_DISCONNECT");
|
||
|
break;
|
||
|
case STATUS_ADDRESS_ALREADY_ASSOCIATED:
|
||
|
Message = TEXT("STATUS_ADDRESS_ALREADY_ASSOCIATED");
|
||
|
break;
|
||
|
case STATUS_ADDRESS_NOT_ASSOCIATED:
|
||
|
Message = TEXT("STATUS_ADDRESS_NOT_ASSOCIATED");
|
||
|
break;
|
||
|
case STATUS_INVALID_CONNECTION:
|
||
|
Message = TEXT("STATUS_INVALID_CONNECTION");
|
||
|
break;
|
||
|
case STATUS_CONNECTION_INVALID:
|
||
|
Message = TEXT("STATUS_CONNECTION_INVALID");
|
||
|
break;
|
||
|
case STATUS_CONNECTION_DISCONNECTED:
|
||
|
Message = TEXT("STATUS_CONNECTION_DISCONNECTED");
|
||
|
break;
|
||
|
case STATUS_INVALID_ADDRESS_COMPONENT:
|
||
|
Message = TEXT("STATUS_INVALID_ADDRESS_COMPONENT");
|
||
|
break;
|
||
|
case STATUS_LOCAL_DISCONNECT:
|
||
|
Message = TEXT("STATUS_LOCAL_DISCONNECT");
|
||
|
break;
|
||
|
case STATUS_LINK_TIMEOUT:
|
||
|
Message = TEXT("STATUS_LINK_TIMEOUT");
|
||
|
break;
|
||
|
case STATUS_IO_TIMEOUT:
|
||
|
Message = TEXT("STATUS_IO_TIMEOUT");
|
||
|
break;
|
||
|
case STATUS_REMOTE_NOT_LISTENING:
|
||
|
Message = TEXT("STATUS_REMOTE_NOT_LISTENING");
|
||
|
break;
|
||
|
case STATUS_BAD_NETWORK_PATH:
|
||
|
Message = TEXT("STATUS_BAD_NETWORK_PATH");
|
||
|
break;
|
||
|
|
||
|
case TDI_STATUS_TIMEDOUT:
|
||
|
Message = TEXT("TDI_STATUS_TIMEDOUT");
|
||
|
break;
|
||
|
default:
|
||
|
_stprintf(UnknownMess, TEXT("STATUS_UNKNOWN [0x%x]"), lStatus);
|
||
|
Message = UnknownMess;
|
||
|
break;
|
||
|
};
|
||
|
|
||
|
return Message;
|
||
|
}
|
||
|
|
||
|
|
||
|
// ---------------------------------------------------------
|
||
|
//
|
||
|
// Function: DoPrintAddress
|
||
|
//
|
||
|
// Arguments: pTransportAddress -- address to print
|
||
|
//
|
||
|
// Returns: none
|
||
|
//
|
||
|
// Descript: This function prints the address information
|
||
|
// of the address passed in
|
||
|
//
|
||
|
// ----------------------------------------------------------
|
||
|
|
||
|
VOID
|
||
|
DoPrintAddress(PTRANSPORT_ADDRESS pTransportAddress)
|
||
|
{
|
||
|
switch(pTransportAddress->Address[0].AddressType)
|
||
|
{
|
||
|
case TDI_ADDRESS_TYPE_IP:
|
||
|
{
|
||
|
PTDI_ADDRESS_IP pTdiAddressIp
|
||
|
= (PTDI_ADDRESS_IP)pTransportAddress->Address[0].Address;
|
||
|
PUCHAR pucTemp
|
||
|
= (PUCHAR)&pTdiAddressIp->in_addr;
|
||
|
|
||
|
_tprintf(TEXT("TDI_ADDRESS_TYPE_IP\n")
|
||
|
TEXT("sin_port = 0x%04x\n")
|
||
|
TEXT("in_addr = %u.%u.%u.%u\n"),
|
||
|
pTdiAddressIp->sin_port,
|
||
|
pucTemp[0], pucTemp[1],
|
||
|
pucTemp[2], pucTemp[3]);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case TDI_ADDRESS_TYPE_IPX:
|
||
|
{
|
||
|
PTDI_ADDRESS_IPX pTdiAddressIpx
|
||
|
= (PTDI_ADDRESS_IPX)pTransportAddress->Address[0].Address;
|
||
|
|
||
|
_tprintf(TEXT("TDI_ADDRESS_TYPE_IPX\n")
|
||
|
TEXT("NetworkAddress = 0x%08x\n")
|
||
|
TEXT("NodeAddress = %u.%u.%u.%u.%u.%u\n")
|
||
|
TEXT("Socket = 0x%04x\n"),
|
||
|
pTdiAddressIpx->NetworkAddress,
|
||
|
pTdiAddressIpx->NodeAddress[0],
|
||
|
pTdiAddressIpx->NodeAddress[1],
|
||
|
pTdiAddressIpx->NodeAddress[2],
|
||
|
pTdiAddressIpx->NodeAddress[3],
|
||
|
pTdiAddressIpx->NodeAddress[4],
|
||
|
pTdiAddressIpx->NodeAddress[5],
|
||
|
pTdiAddressIpx->Socket);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case TDI_ADDRESS_TYPE_NETBIOS:
|
||
|
{
|
||
|
PTDI_ADDRESS_NETBIOS pTdiAddressNetbios
|
||
|
= (PTDI_ADDRESS_NETBIOS)pTransportAddress->Address[0].Address;
|
||
|
TCHAR pucName[17];
|
||
|
|
||
|
//
|
||
|
// make sure we have a zero-terminated name to print...
|
||
|
//
|
||
|
memcpy(pucName, pTdiAddressNetbios->NetbiosName, 16 * sizeof(TCHAR));
|
||
|
pucName[16] = 0;
|
||
|
|
||
|
_putts(TEXT("TDI_ADDRESS_TYPE_NETBIOS\n")
|
||
|
TEXT("NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_"));
|
||
|
|
||
|
switch (pTdiAddressNetbios->NetbiosNameType)
|
||
|
{
|
||
|
case TDI_ADDRESS_NETBIOS_TYPE_UNIQUE:
|
||
|
_putts(TEXT("UNIQUE\n"));
|
||
|
break;
|
||
|
case TDI_ADDRESS_NETBIOS_TYPE_GROUP:
|
||
|
_putts(TEXT("GROUP\n"));
|
||
|
break;
|
||
|
case TDI_ADDRESS_NETBIOS_TYPE_QUICK_UNIQUE:
|
||
|
_putts(TEXT("QUICK_UNIQUE\n"));
|
||
|
break;
|
||
|
case TDI_ADDRESS_NETBIOS_TYPE_QUICK_GROUP:
|
||
|
_putts(TEXT("QUICK_GROUP\n"));
|
||
|
break;
|
||
|
default:
|
||
|
_tprintf(TEXT("INVALID [0x%04x]\n"),
|
||
|
pTdiAddressNetbios->NetbiosNameType);
|
||
|
break;
|
||
|
}
|
||
|
_tprintf(TEXT("NetbiosName = %s\n"), pucName);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
// -----------------------------------------------------------------
|
||
|
//
|
||
|
// Function: TdiLibDeviceIO
|
||
|
//
|
||
|
// Arguments: ulCommandCode -- command code of operation to perform
|
||
|
// pSendBuffer -- data structure containing arguments for driver
|
||
|
// pReceiveBuffer-- data structure containing return values from
|
||
|
// driver
|
||
|
// NOTE: all are passed thru unchanged to DeviceIoControl
|
||
|
//
|
||
|
// Returns: Final status of operation -- STATUS_SUCCESS or failure code
|
||
|
//
|
||
|
// Descript: This function acts as a "wrapper" for DeviceIoControl, and is
|
||
|
// used by those functions that really want a synchronous call,
|
||
|
// but don't want to be hung up in the driver. If a call to
|
||
|
// DeviceIoControl pends, this function waits for up to a minute
|
||
|
// for it to complete. If it doesn't complete within a minute,
|
||
|
// it assumes something is drastically wrong and returns a time-
|
||
|
// out error. If a function completes before then, it gets the
|
||
|
// final completion code and returns that. Hence,
|
||
|
// STATUS_PENDING should never be returned by this function.
|
||
|
//
|
||
|
// Status: ok
|
||
|
//
|
||
|
// -----------------------------------------------------------------
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
TdiLibDeviceIO(ULONG ulCommandCode,
|
||
|
PSEND_BUFFER pSendBuffer,
|
||
|
PRECEIVE_BUFFER pReceiveBuffer)
|
||
|
|
||
|
{
|
||
|
NTSTATUS lStatus; // final status from command
|
||
|
OVERLAPPED *pOverLapped // structure for asynchronous completion
|
||
|
= (OVERLAPPED *)LocalAllocateMemory(sizeof(OVERLAPPED));
|
||
|
|
||
|
//
|
||
|
// create the event to wait on
|
||
|
//
|
||
|
pOverLapped->hEvent = CreateEvent(NULL, // non-inheritable
|
||
|
TRUE, // manually signalled
|
||
|
TRUE, // initially signalled
|
||
|
NULL); // un-named
|
||
|
|
||
|
//
|
||
|
// need the event object to do asynchronous calls
|
||
|
//
|
||
|
if (pOverLapped->hEvent != NULL)
|
||
|
{
|
||
|
pOverLapped->Offset = 0;
|
||
|
pOverLapped->OffsetHigh = 0;
|
||
|
|
||
|
lStatus = TdiLibStartDeviceIO(ulCommandCode,
|
||
|
pSendBuffer,
|
||
|
pReceiveBuffer,
|
||
|
pOverLapped);
|
||
|
|
||
|
if (lStatus == STATUS_PENDING)
|
||
|
{
|
||
|
ULONG ulTimeOut = 60; // 60 seconds
|
||
|
|
||
|
for (;;)
|
||
|
{
|
||
|
lStatus = TdiLibWaitForDeviceIO(pOverLapped);
|
||
|
if (lStatus == STATUS_SUCCESS)
|
||
|
{
|
||
|
lStatus = pReceiveBuffer->lStatus;
|
||
|
break;
|
||
|
}
|
||
|
else if (lStatus == TDI_STATUS_TIMEDOUT)
|
||
|
{
|
||
|
if (--ulTimeOut == 0)
|
||
|
{
|
||
|
SEND_BUFFER SendBuffer;
|
||
|
RECEIVE_BUFFER ReceiveBuffer;
|
||
|
|
||
|
TdiLibDeviceIO(ulABORT_COMMAND,
|
||
|
&SendBuffer,
|
||
|
&ReceiveBuffer);
|
||
|
|
||
|
ulTimeOut = 60;
|
||
|
}
|
||
|
}
|
||
|
else // some type of error case
|
||
|
{
|
||
|
lStatus = STATUS_UNSUCCESSFUL;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
CloseHandle(pOverLapped->hEvent);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// get here if CreateEvent failed
|
||
|
//
|
||
|
else
|
||
|
{
|
||
|
OutputDebugString(TEXT("TdiLibDeviceIo: CreateEvent failed\n"));
|
||
|
lStatus = STATUS_UNSUCCESSFUL;
|
||
|
}
|
||
|
|
||
|
if (lStatus != TDI_STATUS_TIMEDOUT)
|
||
|
{
|
||
|
LocalFreeMemory(pOverLapped);
|
||
|
}
|
||
|
if (lStatus == STATUS_SUCCESS)
|
||
|
{
|
||
|
lStatus = pReceiveBuffer->lStatus;
|
||
|
}
|
||
|
return lStatus;
|
||
|
}
|
||
|
|
||
|
|
||
|
// -----------------------------------------------------------------
|
||
|
//
|
||
|
// Function: TdiLibStartDeviceIO
|
||
|
//
|
||
|
// Arguments: ulCommandCode -- control code of operation to perform
|
||
|
// pSendBuffer -- data structure containing arguments for driver
|
||
|
// pReceiveBuffer-- data structure containing return values from
|
||
|
// driver
|
||
|
// pOverlapped -- overlapped structure
|
||
|
// NOTE: all are passed thru unchanged to DeviceIoControl
|
||
|
//
|
||
|
// Returns: Status of operation -- STATUS_PENDING, STATUS_SUCCESS, or failure code
|
||
|
//
|
||
|
// Descript: This function acts as a "wrapper" for DeviceIoControl, and is
|
||
|
// used by those functions that need an asynchronous call. It
|
||
|
// is used in association with TdiWaitForDeviceIO (which
|
||
|
// checks to see if it is complete)
|
||
|
//
|
||
|
// Status: ok
|
||
|
//
|
||
|
// -----------------------------------------------------------------
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
TdiLibStartDeviceIO(ULONG ulCommandCode,
|
||
|
PSEND_BUFFER pSendBuffer,
|
||
|
PRECEIVE_BUFFER pReceiveBuffer,
|
||
|
OVERLAPPED *pOverLapped)
|
||
|
|
||
|
{
|
||
|
NTSTATUS lStatus; // final status...
|
||
|
ULONG ulBytesReturned; // bytes stored in OutBuffer
|
||
|
ULONG fResult; // immediate result of DeviceIoControl
|
||
|
|
||
|
//
|
||
|
// following call to the driver will return TRUE on SUCCESS_SUCCESS,
|
||
|
// FALSE on everything else
|
||
|
//
|
||
|
EnterCriticalSection(&LibCriticalSection);
|
||
|
fResult = DeviceIoControl(hTdiSampleDriver,
|
||
|
ulTdiCommandToIoctl(ulCommandCode),
|
||
|
pSendBuffer,
|
||
|
sizeof(SEND_BUFFER),
|
||
|
pReceiveBuffer,
|
||
|
sizeof(RECEIVE_BUFFER),
|
||
|
&ulBytesReturned,
|
||
|
pOverLapped);
|
||
|
LeaveCriticalSection(&LibCriticalSection);
|
||
|
|
||
|
if (!fResult)
|
||
|
{
|
||
|
lStatus = GetLastError();
|
||
|
if (lStatus != ERROR_IO_PENDING)
|
||
|
{
|
||
|
OutputDebugString(TEXT("TdiLibStartDeviceIO: DeviceIoControl failed!\n"));
|
||
|
return STATUS_UNSUCCESSFUL;
|
||
|
}
|
||
|
return STATUS_PENDING;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// gets to here if DeviceIoControl returned SUCCESS
|
||
|
//
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
// ----------------------------------------------------------------
|
||
|
//
|
||
|
// Function: TdiLibWaitForDeviceIO
|
||
|
//
|
||
|
// Arguments: hEvent -- event handle associated with asynchronous
|
||
|
// deviceio
|
||
|
// pOverlapped -- overlap structure (so we can get at results)
|
||
|
//
|
||
|
// Returns: final ntstatus of asynchronous operation
|
||
|
//
|
||
|
// Descript: This function is used to wait for the completion of an
|
||
|
// asynchronous deviceio call started by TdiStartDeviceIO
|
||
|
//
|
||
|
// Status: ok
|
||
|
//
|
||
|
// ----------------------------------------------------------------
|
||
|
|
||
|
|
||
|
const ULONG ulONE_SECOND = 1000; // milliseconds in a second
|
||
|
|
||
|
NTSTATUS
|
||
|
TdiLibWaitForDeviceIO(OVERLAPPED *pOverLapped)
|
||
|
|
||
|
{
|
||
|
NTSTATUS lStatus; // final status
|
||
|
ULONG ulBytesReturned; // bytes written to outputbuffer
|
||
|
|
||
|
//
|
||
|
// DeviceIoControl in TdiStartDeviceIO pended.
|
||
|
// Will wait for 1 second before timing out....
|
||
|
//
|
||
|
lStatus = WaitForSingleObject(pOverLapped->hEvent, ulONE_SECOND);
|
||
|
if (lStatus == WAIT_OBJECT_0)
|
||
|
{
|
||
|
if (GetOverlappedResult(hTdiSampleDriver,
|
||
|
pOverLapped,
|
||
|
&ulBytesReturned,
|
||
|
TRUE))
|
||
|
{
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
else // unexpected error case
|
||
|
{
|
||
|
OutputDebugString(TEXT("TdiLibWaitForDeviceIO: Pended DeviceIoControl failed\n"));
|
||
|
}
|
||
|
}
|
||
|
else if (lStatus == WAIT_TIMEOUT)
|
||
|
{
|
||
|
return TDI_STATUS_TIMEDOUT;
|
||
|
}
|
||
|
//
|
||
|
// unexpected return from WaitForSingleObject. Assume an error
|
||
|
//
|
||
|
else
|
||
|
{
|
||
|
OutputDebugString(TEXT("TdiLibWaitForDeviceIO: Pended DeviceIoControl had an error..\n"));
|
||
|
}
|
||
|
return STATUS_UNSUCCESSFUL;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
// end of file utils.cpp
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|