536 lines
16 KiB
C++
536 lines
16 KiB
C++
/*++
|
||
|
||
Copyright (c) 1995 Intel Corp
|
||
Copyright (c) 1996 - 2000 Microsoft Corporation
|
||
|
||
File Name:
|
||
|
||
dt_dll.cpp
|
||
|
||
Abstract:
|
||
|
||
Contains main and supporting functions for a Debug/Trace
|
||
DLL for the WinSock2 DLL. See the design spec
|
||
for more information.
|
||
|
||
--*/
|
||
|
||
//
|
||
// Include Files
|
||
//
|
||
|
||
#include "nowarn.h" /* turn off benign warnings */
|
||
#ifndef _WINSOCKAPI_
|
||
#define _WINSOCKAPI_ /* Prevent inclusion of winsock.h in windows.h */
|
||
#endif
|
||
#include <windows.h>
|
||
#include "nowarn.h" /* some warnings may have been turned back on */
|
||
#include <winsock2.h>
|
||
#include <stdarg.h>
|
||
#include <ws2spi.h>
|
||
#include <commdlg.h>
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <strsafe.h>
|
||
|
||
#include "dt_dll.h"
|
||
#include "cstack.h"
|
||
#include "dt.h"
|
||
#include "handlers.h"
|
||
|
||
//
|
||
// Forward References for Functions
|
||
//
|
||
|
||
BOOL WINAPI
|
||
DllMain(
|
||
HINSTANCE DllInstHandle,
|
||
DWORD Reason,
|
||
LPVOID Reserved);
|
||
|
||
//
|
||
// Externally Visible Global Variables
|
||
//
|
||
|
||
HANDLE LogFileHandle=INVALID_HANDLE_VALUE;// handle to the log file
|
||
ULONG OutputStyle=NO_OUTPUT;
|
||
char Buffer[TEXT_LEN]; // buffer for building output strings
|
||
char *szDtRegKey="System\\CurrentControlSet\\Services\\Winsock2\\Parameters\\DT_DLL_App_Data";
|
||
|
||
//
|
||
// Static Global Variables
|
||
//
|
||
|
||
// name for my window class
|
||
static HINSTANCE DllInstHandle; // handle to the dll instance
|
||
static DWORD TlsIndex=0xFFFFFFFF; // tls index for this module
|
||
static CRITICAL_SECTION CrSec; // critical section for text output
|
||
static HANDLE TextOutEvent; // set when debug window is ready
|
||
|
||
static char LogFileName[MAX_PATH+1]; // name of the log file
|
||
static char ModuleFileName[MAX_PATH+1]; // name of the application
|
||
|
||
// function pointer tables for handler functions.
|
||
static LPFNDTHANDLER HdlFuncTable[MAX_DTCODE + 1];
|
||
|
||
//
|
||
// Function Definitions
|
||
//
|
||
|
||
|
||
BOOL WINAPI
|
||
DllMain(
|
||
HINSTANCE InstanceHandle,
|
||
DWORD Reason,
|
||
LPVOID Reserved)
|
||
/*++
|
||
|
||
DllMain()
|
||
|
||
Function Description:
|
||
|
||
Please see Windows documentation for DllEntryPoint.
|
||
|
||
Arguments:
|
||
|
||
Please see windows documentation.
|
||
|
||
Return Value:
|
||
|
||
Please see windows documentation.
|
||
|
||
--*/
|
||
{
|
||
|
||
Cstack_c *ThreadCstack; // points to Cstack objects in tls
|
||
PINITDATA InitDataPtr; // to pass to the window creation thread
|
||
HKEY hkeyAppData;
|
||
char szSubKeyStr[sizeof(szDtRegKey)+256],
|
||
*ptr=NULL;
|
||
int ModuleLen=0;
|
||
|
||
|
||
// OutputDebugString ("DllMain called.\n");
|
||
switch(Reason) {
|
||
|
||
// Determine the reason for the call and act accordingly.
|
||
case DLL_PROCESS_ATTACH:
|
||
|
||
if ((ModuleLen = GetModuleFileName (NULL, ModuleFileName, sizeof (ModuleFileName)))==0)
|
||
return FALSE;
|
||
|
||
|
||
// Allocate a TLS index.
|
||
TlsIndex = TlsAlloc();
|
||
if (TlsIndex==0xFFFFFFFF)
|
||
return FALSE;
|
||
|
||
DllInstHandle = InstanceHandle;
|
||
try {
|
||
InitializeCriticalSection(&CrSec);
|
||
}
|
||
catch(...) {
|
||
OutputStyle = NO_OUTPUT;
|
||
return FALSE;
|
||
}
|
||
|
||
TextOutEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||
if (TextOutEvent==NULL)
|
||
return FALSE;
|
||
|
||
// Fill in the handler function table.
|
||
DTHandlerInit(HdlFuncTable, MAX_DTCODE);
|
||
|
||
// Build the log file name
|
||
StringCchCopy( LogFileName, MAX_PATH+1, ModuleFileName );
|
||
StringCchCat( LogFileName, MAX_PATH+1, ".log");
|
||
|
||
// See if the reg key exists for this EXE
|
||
ptr = &ModuleFileName[ModuleLen-1];
|
||
while ( (ptr != ModuleFileName) && (*ptr != '\\') )
|
||
ptr--;
|
||
if (*ptr == '\\')
|
||
ptr++;
|
||
|
||
// Build the key
|
||
|
||
StringCchPrintf(szSubKeyStr, sizeof(szDtRegKey)+255, "%s\\%s", szDtRegKey, ptr);
|
||
|
||
OutputDebugString("Looking for key: ");
|
||
OutputDebugString(szSubKeyStr);
|
||
OutputDebugString("\r\n");
|
||
|
||
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||
szSubKeyStr,
|
||
0,
|
||
KEY_QUERY_VALUE,
|
||
&hkeyAppData) == NO_ERROR)
|
||
{
|
||
OutputDebugString("Found the registry key\r\n");
|
||
OutputStyle = FILE_ONLY;
|
||
|
||
RegCloseKey(hkeyAppData);
|
||
}
|
||
else
|
||
{
|
||
OutputStyle = NO_OUTPUT;
|
||
}
|
||
|
||
if (OutputStyle == FILE_ONLY)
|
||
{
|
||
LogFileHandle = CreateFile(LogFileName,
|
||
GENERIC_WRITE,
|
||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||
NULL,
|
||
CREATE_ALWAYS,
|
||
FILE_ATTRIBUTE_NORMAL,
|
||
NULL);
|
||
if (LogFileHandle == INVALID_HANDLE_VALUE) {
|
||
OutputDebugString("Unable to create log file!\r\n");
|
||
OutputStyle = NO_OUTPUT;
|
||
}
|
||
}
|
||
|
||
// Get some information for later output to the debug window
|
||
// or file -- get the time, PID, and TID of the calling
|
||
// process and put into a INITDATA struct. This memory will
|
||
// be freed by the thread it is passed to.
|
||
InitDataPtr = (PINITDATA) LocalAlloc(0, sizeof(INITDATA));
|
||
GetLocalTime(&(InitDataPtr->LocalTime));
|
||
InitDataPtr->TID = GetCurrentThreadId();
|
||
InitDataPtr->PID = GetCurrentProcessId();
|
||
|
||
// Normally the window thread does a DTTextOut of the time
|
||
// and process info that we saved just above. But in this
|
||
// case, there is no window thread so spit it out to the
|
||
// file or debugger.
|
||
|
||
StringCchPrintf(Buffer, TEXT_LEN-1, "Log initiated: %d-%d-%d, %d:%d:%d\r\n",
|
||
InitDataPtr->LocalTime.wMonth,
|
||
InitDataPtr->LocalTime.wDay,
|
||
InitDataPtr->LocalTime.wYear,
|
||
InitDataPtr->LocalTime.wHour,
|
||
InitDataPtr->LocalTime.wMinute,
|
||
InitDataPtr->LocalTime.wSecond);
|
||
DTTextOut(LogFileHandle, Buffer, OutputStyle);
|
||
StringCchPrintf(Buffer, TEXT_LEN-1, "Process ID: 0x%X Thread ID: 0x%X\r\n",
|
||
InitDataPtr->PID,
|
||
InitDataPtr->TID);
|
||
DTTextOut(LogFileHandle, Buffer, OutputStyle);
|
||
|
||
// Setting this event allows {Pre|Post}ApiNotify to
|
||
// proceed. This event isn't really needed in this case
|
||
// (because there is only one thread, and we know the code
|
||
// above has been executed before WSAPre|PostApiNotify).
|
||
SetEvent(TextOutEvent);
|
||
|
||
// flow through...
|
||
|
||
case DLL_THREAD_ATTACH:
|
||
|
||
// Store a pointer to a new Cstack_c in the slot for this
|
||
// thread.
|
||
ThreadCstack = new Cstack_c();
|
||
TlsSetValue(TlsIndex, (LPVOID)ThreadCstack);
|
||
|
||
break;
|
||
|
||
case DLL_PROCESS_DETACH:
|
||
|
||
// Free up some resources. This is like cleaning up your room
|
||
// before the tornado strikes, but hey, it's good practice.
|
||
TlsFree(TlsIndex);
|
||
DeleteCriticalSection(&CrSec);
|
||
|
||
CloseHandle(LogFileHandle);
|
||
|
||
break;
|
||
|
||
case DLL_THREAD_DETACH:
|
||
|
||
// Get the pointer to this thread's Cstack, and delete the
|
||
// object.
|
||
ThreadCstack = (Cstack_c *)TlsGetValue(TlsIndex);
|
||
delete ThreadCstack;
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
break;
|
||
} // switch (Reason)
|
||
|
||
return TRUE;
|
||
} // DllMain()
|
||
|
||
|
||
|
||
|
||
|
||
BOOL WINAPIV
|
||
WSAPreApiNotify(
|
||
IN INT NotificationCode,
|
||
OUT LPVOID ReturnCode,
|
||
IN LPSTR LibraryName,
|
||
...)
|
||
/*++
|
||
|
||
Function Description:
|
||
|
||
Builds a string for output and passes it, along with information
|
||
about the call, to a handler function.
|
||
|
||
Arguments:
|
||
|
||
NotificationCode -- specifies which API function called us.
|
||
|
||
ReturnCode -- a generic pointer to the return value of the API
|
||
function. Can be used to change the return value in the
|
||
case of a short-circuit (see how the return value from
|
||
PreApiNotify works for more information on short-circuiting
|
||
the API function).
|
||
|
||
LibraryName -- a string pointing to the name of the library that
|
||
called us.
|
||
|
||
... -- variable number argument list. These are pointers
|
||
to the actual parameters of the API functions.
|
||
|
||
Return Value:
|
||
|
||
Returns TRUE if we want to short-circuit the API function;
|
||
in other words, returning non-zero here forces the API function
|
||
to return immediately before any other actions take place.
|
||
|
||
Returns FALSE if we want to proceed with the API function.
|
||
|
||
--*/
|
||
{
|
||
va_list vl; // used for variable arg-list parsing
|
||
Cstack_c *ThreadCstack; // the Cstack_c object for this thread
|
||
int Index = 0; // index into string we are creating
|
||
BOOL ReturnValue; // value to return
|
||
LPFNDTHANDLER HdlFunc; // pointer to handler function
|
||
int Counter; // counter popped off the cstack
|
||
int OriginalError; // any pending error is saved
|
||
|
||
if (OutputStyle==NO_OUTPUT)
|
||
return FALSE;
|
||
|
||
OriginalError = GetLastError();
|
||
|
||
EnterCriticalSection(&CrSec);
|
||
|
||
// Wait until the debug window is ready to receive text for output.
|
||
WaitForSingleObject(TextOutEvent, INFINITE);
|
||
va_start(vl, LibraryName);
|
||
|
||
// Get the Cstack_c object for this thread.
|
||
ThreadCstack = (Cstack_c *)TlsGetValue(TlsIndex);
|
||
if (!ThreadCstack){
|
||
ThreadCstack = new Cstack_c();
|
||
TlsSetValue(TlsIndex, (LPVOID)ThreadCstack);
|
||
StringCchPrintf(Buffer, TEXT_LEN-1, "0x%X Foriegn thread\n",
|
||
GetCurrentThreadId());
|
||
DTTextOut(LogFileHandle, Buffer, OutputStyle);
|
||
} //if
|
||
|
||
// Start building an output string with some info that's
|
||
// independent of which API function called us.
|
||
Index = StringCchPrintf(Buffer, TEXT_LEN-1, "Function call: %d ",
|
||
ThreadCstack->CGetCounter());
|
||
|
||
// Push the counter & increment.
|
||
ThreadCstack->CPush();
|
||
|
||
// Reset the error to what it was when the function started.
|
||
SetLastError(OriginalError);
|
||
|
||
// Call the appropriate handling function, output the buffer.
|
||
if ((NotificationCode < MAX_DTCODE) && HdlFuncTable[NotificationCode]) {
|
||
HdlFunc = HdlFuncTable[NotificationCode];
|
||
ReturnValue = (*HdlFunc)(vl, ReturnCode,
|
||
LibraryName,
|
||
Buffer,
|
||
Index,
|
||
TEXT_LEN,
|
||
TRUE);
|
||
|
||
} else {
|
||
|
||
StringCchPrintf(Buffer + Index, TEXT_LEN - Index - 1, "Unknown function called!\r\n");
|
||
DTTextOut(LogFileHandle, Buffer, OutputStyle);
|
||
ReturnValue = FALSE;
|
||
}
|
||
|
||
// If we are returning TRUE, then the API/SPI function will be
|
||
// short-circuited. We must pop the thread stack, since no
|
||
// corresponding WSAPostApiNotify will be called.
|
||
if (ReturnValue) {
|
||
ThreadCstack->CPop(Counter);
|
||
}
|
||
|
||
LeaveCriticalSection(&CrSec);
|
||
// In case the error has changed since the handler returned, we
|
||
// want to set it back.
|
||
SetLastError(OriginalError);
|
||
return(ReturnValue);
|
||
|
||
} // WSAPreApiNotify()
|
||
|
||
|
||
|
||
|
||
|
||
|
||
BOOL WINAPIV
|
||
WSAPostApiNotify(
|
||
IN INT NotificationCode,
|
||
OUT LPVOID ReturnCode,
|
||
IN LPSTR LibraryName,
|
||
...)
|
||
/*++
|
||
|
||
PostApiNotify()
|
||
|
||
Function Description:
|
||
|
||
Like PreApiNotify, builds a string and passes it, along with
|
||
information about the call, to a handler function.
|
||
|
||
Arguments:
|
||
|
||
NotificationCode -- specifies which API function called us.
|
||
|
||
ReturnCode -- a generic pointer to the return value of the API
|
||
function.
|
||
|
||
... -- variable number argument list. These are pointers
|
||
to the actual parameters of the API functions.
|
||
|
||
Return Value:
|
||
|
||
Returns value is currently meaningless.
|
||
|
||
--*/
|
||
{
|
||
va_list vl; // used for variable arg-list parsing
|
||
Cstack_c *ThreadCstack; // the Cstack_c object for this thread
|
||
int Index = 0; // index into string we are creating
|
||
int Counter; // counter we pop off the cstack
|
||
LPFNDTHANDLER HdlFunc; // pointer to handler function
|
||
int OriginalError; // any pending error is saved
|
||
|
||
if (OutputStyle==NO_OUTPUT)
|
||
return FALSE;
|
||
|
||
OriginalError = GetLastError();
|
||
|
||
EnterCriticalSection(&CrSec);
|
||
|
||
// Wait until it's ok to send output.
|
||
WaitForSingleObject(TextOutEvent, INFINITE);
|
||
|
||
va_start(vl, LibraryName);
|
||
|
||
// Get the cstack object from TLS, pop the Counter.
|
||
ThreadCstack = (Cstack_c *) TlsGetValue(TlsIndex);
|
||
|
||
if (!ThreadCstack){
|
||
ThreadCstack = new Cstack_c();
|
||
TlsSetValue(TlsIndex, (LPVOID)ThreadCstack);
|
||
StringCchPrintf(Buffer, TEXT_LEN-1, "0x%X Foriegn thread\n",
|
||
GetCurrentThreadId());
|
||
DTTextOut(LogFileHandle, Buffer, OutputStyle);
|
||
} //if
|
||
|
||
ThreadCstack->CPop(Counter);
|
||
|
||
Index = StringCchPrintf(Buffer, TEXT_LEN-1, "Function Call: %d ", Counter);
|
||
|
||
// Set the error to what it originally was.
|
||
SetLastError(OriginalError);
|
||
|
||
// Call the appropriate handling function, output the buffer.
|
||
if ((NotificationCode < MAX_DTCODE) && HdlFuncTable[NotificationCode]) {
|
||
HdlFunc = HdlFuncTable[NotificationCode];
|
||
(*HdlFunc)(vl, ReturnCode,
|
||
LibraryName,
|
||
Buffer,
|
||
Index,
|
||
TEXT_LEN,
|
||
FALSE);
|
||
} else {
|
||
|
||
StringCchPrintf(Buffer + Index, TEXT_LEN - Index - 1, "Unknown function returned!\r\n");
|
||
DTTextOut(LogFileHandle, Buffer, OutputStyle);
|
||
}
|
||
|
||
LeaveCriticalSection(&CrSec);
|
||
// In case the error has changed since the handler returned, we
|
||
// want to set it back.
|
||
SetLastError(OriginalError);
|
||
return(FALSE);
|
||
|
||
} // WSAPostApiNotify()
|
||
|
||
|
||
BOOL
|
||
DTTextOut(
|
||
IN HANDLE FileHandle,
|
||
IN char *String,
|
||
DWORD Style)
|
||
/*++
|
||
|
||
DTTextOut()
|
||
|
||
Function Description:
|
||
|
||
This function outputs a string to a debug window and/or file.
|
||
|
||
Arguments:
|
||
|
||
FileHandle -- handle to an open file for debug output.
|
||
|
||
String -- the string to output.
|
||
|
||
Style -- specifies whether the output should go to the window,
|
||
the file, or both.
|
||
|
||
Return Value:
|
||
|
||
Returns TRUE if the output succeeds, FALSE otherwise.
|
||
|
||
--*/
|
||
{
|
||
#define SCRATCH_BUFFER (TEXT_LEN + 60)
|
||
|
||
DWORD NumWritten; // WriteFile takes an address to this
|
||
BOOL Result; // result of WriteFile
|
||
char Output[SCRATCH_BUFFER]; // scratch buffer
|
||
|
||
static DWORD LineCount = 0; // text output line number
|
||
DWORD BufIndex = 0; // index into output string
|
||
|
||
if ((Style==NO_OUTPUT) || (FileHandle == INVALID_HANDLE_VALUE))
|
||
return TRUE;
|
||
|
||
// Build a new string with the line-number and pid.tid in front.
|
||
BufIndex += StringCchPrintf(Output, SCRATCH_BUFFER-1, "(%d-%X.%X) ", LineCount++,
|
||
GetCurrentProcessId (),
|
||
GetCurrentThreadId ());
|
||
StringCbCatN(Output, sizeof(Output),String, SCRATCH_BUFFER - BufIndex - 1);
|
||
|
||
Result = WriteFile(FileHandle, (LPCVOID)Output, (int) strlen(Output),
|
||
&NumWritten, NULL);
|
||
if (!Result) {
|
||
|
||
CloseHandle(FileHandle);
|
||
FileHandle = INVALID_HANDLE_VALUE;
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
|
||
} // DTTextOut()
|