windows-nt/Source/XPSP1/NT/net/tdi/sample/lib/utils.cpp
2020-09-26 16:20:57 +08:00

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
////////////////////////////////////////////////////////////////////////////