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