Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

784 lines
21 KiB

/*++
Copyright (c) 1992-2001 Microsoft Corporation
Module Name:
mqrcvr.cpp
Abstract:
Receives file names from server and launches debugger
--*/
//
// Includes
//
#ifndef MQEXTDLL
#include <stdio.h>
#include <windows.h>
#include <objbase.h>
#define dprintf printf
#else
#include "mqext.h"
#endif
//
// Unique include file for ActiveX MSMQ apps
//
#include <mqoai.h>
#include <mq.h>
#include <strsafe.h>
//
// Various defines
//
#define MAX_VAR 20
#define MAX_BUFFER 500
//
// GUID created with the tool "GUIDGEN"
//
static WCHAR strGuidMQTestType[] =
L"{c30e0960-a2c0-11cf-9785-00608cb3e80c}";
//
// Prototypes
//
void PrintError(char *s, HRESULT hr);
HRESULT Syntax();
char g_DebuggerName[MAX_PATH];
char g_SymCache[MAX_PATH];
char g_ServerMachine[MAX_COMPUTERNAME_LENGTH*4 + 1];
char g_FormatName[MAX_PATH] = {0};
char g_QueueName[100];
CHAR g_DumpPath[MAX_PATH + 1];
BOOL g_Retriage = FALSE;
BOOL g_NoCustomer = FALSE;
BOOL g_SendMail = FALSE;
ULONG g_MaxMemUsage = 50;
ULONG g_PauseForNext = 1000;
BOOL g_CreateQ = 0;
BOOL g_bSend = FALSE;
// Some useful macros
#define RELEASE(punk) if (punk) { (punk)->Release(); (punk) = NULL; }
#define ADDREF(punk) ((punk) ? (punk)->AddRef() : 0)
#define PRINTERROR(s, hr) { PrintError(s, hr); goto Cleanup; }
BOOL
GetArgs(int Argc, CHAR ** Argv)
{
int i = 1;
g_ServerMachine[0] = 0;
g_QueueName[0] = 0;
StringCchCopy(g_DebuggerName, sizeof(g_DebuggerName), "c:\\Debuggers\\ocakd.exe");
StringCchCopy(g_SymCache, sizeof(g_SymCache), "c:\\symcache");
g_bSend = FALSE;
while (i<Argc)
{
if (!strcmp(Argv[i], "-create"))
{
++i;
g_CreateQ = TRUE;
}
else if (!strcmp(Argv[i],"-d"))
{
// Get sender format name
++i;
if ((i < Argc) &&
(strlen(Argv[i]) < MAX_PATH))
{
StringCchCopy(g_DebuggerName, sizeof(g_DebuggerName), Argv[i]);
++i;
}
}
else if (!strcmp(Argv[i],"-f"))
{
// Get sender format name
++i;
if ((i < Argc) &&
(strlen(Argv[i]) < MAX_PATH))
{
StringCchCopy(g_FormatName, sizeof(g_FormatName), Argv[i]);
++i;
}
}
else if (!strcmp(Argv[i], "-m"))
{
++i;
// get memory usage value
if (i<Argc)
{
g_MaxMemUsage = atoi(Argv[i]);
++i;
}
}
else if (!strcmp(Argv[i], "-mail"))
{
++i;
g_SendMail = TRUE;
}
else if (!strcmp(Argv[i], "-nocust"))
{
++i;
g_NoCustomer = TRUE;
}
else if (!strcmp(Argv[i], "-p") ||
!strcmp(Argv[i], "-pause"))
{
++i;
// get memory usage value
if (i<Argc)
{
g_PauseForNext = atoi(Argv[i]);
++i;
}
}
else if (!strcmp(Argv[i], "-q"))
{
++i;
// Get Queue name
if ((i < Argc) &&
(strlen(Argv[i]) < sizeof(g_QueueName)))
{
StringCchCopy(g_QueueName, sizeof(g_QueueName), Argv[i]);
++i;
}
}
else if (!strcmp(Argv[i],"-retriage"))
{
// Get sender server machine name
++i;
g_Retriage = TRUE;
}
else if (!strcmp(Argv[i],"-s"))
{
// Get sender server machine name
++i;
if ((i < Argc) &&
(strlen(Argv[i]) < MAX_COMPUTERNAME_LENGTH*4))
{
StringCchCopy(g_ServerMachine, sizeof(g_ServerMachine), Argv[i]);
++i;
}
}
else if (!strcmp(Argv[i],"-send"))
{
// Get sender server machine name
++i;
g_bSend = TRUE;
}
else if (!strcmp(Argv[i],"-y"))
{
++i;
if ((i < Argc) &&
(strlen(Argv[i]) < MAX_PATH))
{
StringCchCopy(g_SymCache, sizeof(g_SymCache), Argv[i]);
++i;
}
}
else
{
printf("Unkonwn argument %s\n", Argv[i]);
return FALSE;
}
}
return (g_ServerMachine[0] && g_QueueName[0]) || g_FormatName[0] ;
}
/*
LaunchDebugger - Launches a debugger process
Input : g_DumpPath has the dump file name to run debugger on
fWait - Wait for process to finish
Return: Succesful creation of process or the process exit code
*/
HRESULT
LaunchDebugger(BOOL fWait)
{
STARTUPINFO StartupInfo;
PROCESS_INFORMATION ProcessInfo;
ULONG ExitCode;
TCHAR CommandLine[2048];
HRESULT hr;
ZeroMemory(&StartupInfo,sizeof(STARTUPINFO));
StartupInfo.cb = sizeof(STARTUPINFO);
StringCbPrintf(CommandLine, sizeof(CommandLine),
"%s -i srv*%s*\\\\symbols\\symbols -y srv*%s*\\\\symbols\\symbols -z %s "
"-c \"!dbaddcrash %s %s %s -p %s;q\"",
g_DebuggerName,
g_SymCache,
g_SymCache,
g_DumpPath,
g_Retriage ? ("-retriage") : (""),
g_SendMail ? ("-mail") : (""),
g_NoCustomer ? ("-nocust") : (""),
g_DumpPath);
dprintf("Executing: %s\n", CommandLine);
if (!CreateProcess(g_DebuggerName,
CommandLine,
NULL,
NULL,
FALSE,
CREATE_NEW_CONSOLE,
// CREATE_NO_WINDOW,
NULL,
NULL,
&StartupInfo,
&ProcessInfo))
{
hr = GetLastError();
dprintf("Failed to launch debugger for %s, error %lx\n",
g_DumpPath, hr);
return hr;
}
else if (fWait)
{
// wait for process to finish
WaitForSingleObject(ProcessInfo.hProcess,INFINITE);
GetExitCodeProcess( ProcessInfo.hProcess, (LPDWORD) &hr);
dprintf ("Debugger Exited with Exit code: %lx",hr);
}
else
{
hr = S_OK;
}
CloseHandle( ProcessInfo.hThread );
CloseHandle( ProcessInfo.hProcess);
return hr;
}
/**************************************************************************************************************
//
// This creates and opens up a MSMQ to send messages. Queue is created / opened on g_ServerMachine and Queue name
// is taken from g_QueueName.
//
// pwszQueueFormatName - Format name identyfying the queue to be opened
//
// pwszQueuePathName - Path name identyfying the queue to be opened, this isn't used when
// pwszQueueFormatName is present
//
// bSendQueue - Specifies whether Queue has send or receive access
//
// On success the queue handle is returned in pStartedQ. bCreated is set depending on whether the Queue was created
// Caller must CloseSendQ after its done sending messages.
//
***************************************************************************************************************/
HRESULT
StartMessageQ(
PWSTR pwszQueueFormatName,
PWSTR pwszQueuePathName,
BOOL bSendQueue,
QUEUEHANDLE* pStartedQ,
BOOL* bCreated)
{
HRESULT Hr = S_OK;
QUEUEHANDLE hQueue;
DWORD i;
if (!pwszQueueFormatName && !pwszQueuePathName )
{
Hr = E_INVALIDARG;
PRINTERROR("No queue connection string specified", Hr);
}
if (g_CreateQ)
{
MQQUEUEPROPS QueueProps;
QUEUEPROPID PropIDs[2];
MQPROPVARIANT PropVariants[2];
HRESULT hrProps[2];
ULONG FormatLength = 0;
i = 0;
if (pwszQueueFormatName)
{
FormatLength = sizeof(WCHAR) * (1 + wcslen(pwszQueueFormatName));
} else if (pwszQueuePathName)
{
PropIDs[i] = PROPID_Q_PATHNAME;
PropVariants[i].vt = VT_LPWSTR;
PropVariants[i].pwszVal = pwszQueuePathName;
i++;
}
PropIDs[i] = PROPID_Q_LABEL;
PropVariants[i].vt = VT_LPWSTR;
PropVariants[i].pwszVal = L"MSMQ for dumpfiles";
i++;
QueueProps.aPropID = PropIDs;
QueueProps.aPropVar = PropVariants;
QueueProps.cProp = i;
QueueProps.aStatus = hrProps;
Hr = MQCreateQueue(NULL,
&QueueProps,
pwszQueueFormatName,
&FormatLength);
if (FAILED(Hr))
{
//
// API Fails, not because the queue exists
//
if (((LONG) Hr) != MQ_ERROR_QUEUE_EXISTS)
PRINTERROR("Cannot create queue", Hr);
}
}
Hr = MQOpenQueue(pwszQueueFormatName,
bSendQueue ? MQ_SEND_ACCESS : MQ_RECEIVE_ACCESS,
MQ_DENY_NONE,
&hQueue);
if (FAILED(Hr))
{
PRINTERROR("MQOpenQueue failed", Hr);
}
if (FAILED(Hr))
{
PRINTERROR("Cannot open queue", Hr);
}
*pStartedQ = (IMSMQQueue*) hQueue;
if (g_CreateQ)
{
*bCreated = TRUE;
}
return S_OK;
Cleanup:
return Hr;
}
/********************************************************************************************
//
// SendMSMQMessage: Sends the message string to the queue
//
// hSendQ QUEUEHANDLE from MQOpenQueue
//
// pwszMessage WCHAR array of message body to be send
//
// pwszMessageLabel WCHAR array specifying message label
//
// Returns S_OK for success
//
*******************************************************************************************/
HRESULT
SendMsmQMessage(
QUEUEHANDLE hSendQ,
PWCHAR pwszMessage,
PWCHAR pwszMessageLabel
)
{
HRESULT Hr = S_OK;
DWORD i;
#define NUM_PROPS 4
MSGPROPID PropIds[NUM_PROPS];
MQPROPVARIANT PropVariants[NUM_PROPS] = {0};
MQMSGPROPS MsgProps = {0};
HRESULT hrProps[NUM_PROPS];
if (!hSendQ)
{
Hr = E_INVALIDARG;
PRINTERROR("Invalid Send Q handle", Hr);
}
i = 0;
PropIds[i] = PROPID_M_LABEL;
PropVariants[i].vt = VT_LPWSTR;
PropVariants[i].pwszVal = pwszMessageLabel;
i++;
PropIds[i] = PROPID_M_BODY;
PropVariants[i].vt = VT_VECTOR|VT_UI1;
PropVariants[i].caub.pElems = (LPBYTE) pwszMessage;
PropVariants[i].caub.cElems = sizeof(WCHAR) * ( 1 + wcslen (pwszMessage) );
i++;
PropIds[i] = PROPID_M_BODY_TYPE;
PropVariants[i].vt = VT_UI4;
PropVariants[i].ulVal = VT_LPWSTR;
PropIds[i] = PROPID_M_TIME_TO_BE_RECEIVED;
PropVariants[i].vt = VT_UI4;
PropVariants[i].ulVal = 60*5;
i++;
MsgProps.cProp = NUM_PROPS;
MsgProps.aPropID = PropIds;
MsgProps.aPropVar = PropVariants;
MsgProps.aStatus = hrProps;
Hr = MQSendMessage(hSendQ, &MsgProps, MQ_NO_TRANSACTION);
if (Hr == MQ_ERROR_PROPERTY)
{
dprintf("MQProperty errors\n");
for (i = 0; i < NUM_PROPS; i++)
{
dprintf("%lx: %8lx --> %08lx\n", i, PropIds[i], hrProps[i]);
}
}
if (FAILED(Hr))
{
PRINTERROR("MQSendMessage failed", Hr);
}
#undef NUM_PROPS
Hr = S_OK;
Cleanup:
return Hr;
}
/****************************************************************************************
// This reveives message from an already opened queue.
//
// hReceiveQ QUEUEHANDLE from MQOpenQueue
//
// pwszMessageBuff WCHAR array for receiving message body
//
// SizeofMessageBuff size of available memory in pwszMessageBuff
//
// pwszMessageLabelBuff WCHAR array for receiving label associated with message
//
// SizeofMessageLabelBuff size of available memory in pwszMessageLabelBuff
//
// Returns S_OK for success
//*************************************************************************************/
HRESULT
ReceiveMsmQMessage(
QUEUEHANDLE hReceiveQ,
PWCHAR pwszMessageBuff,
ULONG SizeofMessageBuff,
PWCHAR pwszMessageLabelBuff,
ULONG SizeofMessageLabelBuff
)
{
HRESULT Hr = S_OK;
#define NUM_RCV_PROPS 5
MSGPROPID PropIds[NUM_RCV_PROPS];
MQPROPVARIANT PropVariants[NUM_RCV_PROPS];
HRESULT hrProps[NUM_RCV_PROPS];
MQMSGPROPS MessageProps;
DWORD i;
if (!hReceiveQ)
{
Hr = E_INVALIDARG;
PRINTERROR("Invalid Receive Q handle", Hr);
}
i = 0;
PropIds[i] = PROPID_M_LABEL_LEN;
PropVariants[i].vt = VT_UI4;
PropVariants[i].ulVal = SizeofMessageLabelBuff;
i++;
PropIds[i] = PROPID_M_LABEL;
PropVariants[i].vt = VT_LPWSTR;
PropVariants[i].pwszVal = pwszMessageLabelBuff;
i++;
PropIds[i] = PROPID_M_BODY_SIZE;
PropVariants[i].vt = VT_UI4;
i++;
PropIds[i] = PROPID_M_BODY_TYPE;
PropVariants[i].vt = VT_UI4;
i++;
PropIds[i] = PROPID_M_BODY;
PropVariants[i].vt = VT_VECTOR|VT_UI1;
PropVariants[i].caub.pElems = (LPBYTE) pwszMessageBuff;
PropVariants[i].caub.cElems = SizeofMessageBuff;
i++;
MessageProps.aPropID = PropIds;
MessageProps.aPropVar = PropVariants;
MessageProps.aStatus = hrProps;
MessageProps.cProp = i;
Hr = MQReceiveMessage(hReceiveQ, -1, MQ_ACTION_RECEIVE,
&MessageProps, NULL, NULL, NULL, MQ_NO_TRANSACTION);
if (Hr == MQ_ERROR_PROPERTY)
{
dprintf("MQProperty errors\n");
for (i = 0; i < NUM_RCV_PROPS; i++)
{
dprintf("%lx: %8lx --> %08lx\n", i, PropIds[i], hrProps[i]);
}
}
if (FAILED(Hr))
{
PRINTERROR("MQReceiveMessage failed", Hr);
}
Cleanup:
return Hr;
}
/******************************************************************************
//
// Close a MsmQ opened with MQOpenQueue
//
// hQueue QUEUEHANDLE from MQOpenQueue
//
// bDeleteQ If set TRUE , queue would be deleted
//
// Returns S_OK on success
//
/*****************************************************************************/
HRESULT
CloseMessageQ(
QUEUEHANDLE hQueue,
BOOL bDeleteQ
)
{
HRESULT Hr = S_OK;
if (!hQueue || FAILED(Hr = MQCloseQueue(hQueue)))
{
PRINTERROR("Cannot close queue", Hr);
}
if (bDeleteQ)
{
// XXX - need a format name
// MQDeleteQueue();
}
if (FAILED(Hr))
{
PRINTERROR("Cannot delete queue", Hr);
}
Cleanup:
return Hr;
}
//--------------------------------------------------------
//
// Receiver Mode
// -------------
// The receiver side does the following:
// 1. Creates a queue on its given computer'
// of type "guidMQTestType".
// 2. Opens the queue
// 3. In a Loop
// Receives messages
// Prints message body and message label
// Launches debugger
// 4. Cleanup handles
// 5. Deletes the queue from the directory service
//
//--------------------------------------------------------
HRESULT Receiver()
{
QUEUEHANDLE pqReceive = NULL;
BSTR bstrFormatName = NULL;
BSTR bstrPathName = NULL;
BSTR bstrServiceType = NULL;
BSTR bstrLabel = NULL;
BSTR bstrMsgLabel = NULL;
VARIANT varIsTransactional, varIsWorldReadable, varBody, varBody2, varWantDestQueue, varWantBody, varReceiveTimeout;
WCHAR wcsPathName[1000];
BOOL fQuit = FALSE;
BOOL Created= FALSE;
HRESULT hresult = NOERROR;
dprintf("\nReceiver for queue %s on machine %s\nLimit memusage to %ld%%\n",
g_QueueName,
g_ServerMachine,
g_MaxMemUsage);
//
// Prepare properties to create a queue on local machine
//
if (g_FormatName[0])
{
// access by formatname
// Set the FormatName
StringCbPrintfW(wcsPathName, sizeof(wcsPathName), L"%S", g_FormatName);
dprintf("Openeing q byt formatname: %ws\n", wcsPathName);
bstrFormatName = SysAllocString(wcsPathName);
if (bstrFormatName == NULL)
{
PRINTERROR("OOM: formatname", E_OUTOFMEMORY);
}
} else
{
// access by pathname
// Set the PathName
StringCbPrintfW(wcsPathName, sizeof(wcsPathName), L"%S\\%S", g_ServerMachine,g_QueueName);
dprintf("Openeing q %ws\n", wcsPathName);
bstrPathName = SysAllocString(wcsPathName);
if (bstrPathName == NULL)
{
PRINTERROR("OOM: pathname", E_OUTOFMEMORY);
}
}
hresult = StartMessageQ(bstrFormatName, bstrPathName, FALSE,
&pqReceive, &Created);
if (FAILED(hresult))
{
PRINTERROR("Cannot start Q", hresult);
}
g_DumpPath[0] = 0;
//
// Main receiver loop
//
dprintf("\nWaiting for messages ...\n");
while (!fQuit)
{
WCHAR BufferMsg[1024], BufferLabel[100];
MEMORYSTATUS stat;
ULONG nWaitCount;
//
// Receive the message
//
hresult = ReceiveMsmQMessage(pqReceive,BufferMsg, sizeof(BufferMsg),
BufferLabel, sizeof(BufferLabel));
if (FAILED(hresult))
{
PRINTERROR("Receive message", hresult);
}
dprintf("%ws : %ws\n", BufferLabel, BufferMsg);
//
// Check for end of app
//
if (_wcsicmp(BufferMsg, L"quit") == 0)
{
fQuit = TRUE;
}
else
{
// Launch the debugger
StringCbPrintfA(g_DumpPath, sizeof(g_DumpPath), "%ws", BufferMsg);
if (LaunchDebugger(FALSE) == S_OK)
{
// done with this dump
g_DumpPath[0] = 0;
}
}
// wait for sometime before launching another process
stat.dwMemoryLoad = -1;
nWaitCount = 0;
while (stat.dwMemoryLoad > g_MaxMemUsage)
{
//
//
// Check CPU load and return when it's below our bound
//
GlobalMemoryStatus(&stat);
nWaitCount++;
if (stat.dwMemoryLoad > g_MaxMemUsage)
{
dprintf("Memory usage now is %ld%%, waiting (%ldms) for usage < %ld%%\r",
stat.dwMemoryLoad,
g_PauseForNext * nWaitCount,
g_MaxMemUsage);
if (nWaitCount > 100)
{
nWaitCount = 100;
}
}
Sleep( g_PauseForNext * nWaitCount );
}
dprintf("Memory usage now is %ld%%, waiting for message ...\r",
stat.dwMemoryLoad);
} /* while (!fQuit) */
// fall through...
Cleanup:
CloseMessageQ(pqReceive, Created);
if (bstrPathName) SysFreeString(bstrPathName);
if (bstrFormatName) SysFreeString(bstrFormatName);
return hresult;
}
/************************************************************************************************
//
// SendMessageText - generic API to send message on an MSMQ, It opens the queue, puts message in it
// and closes the queue.
//
// pwszMsmqFormat - Format name identifying the queue where message is to be sent
//
// pwszMesgLabel - Label for the message to be sent
//
// pwszMesgText - Message to be sent
//
// Reuturns S_OK on sucess
//
*************************************************************************************************/
HRESULT
SendMessageText(
PWCHAR pwszMsmqFormat,
PWCHAR pwszMesgLabel,
PWCHAR pwszMesgText
)
{
HRESULT Hr;
BOOL Created = FALSE;
QUEUEHANDLE hSendQ = NULL;
Hr = StartMessageQ(pwszMsmqFormat, NULL, TRUE,
&hSendQ, &Created);
if (FAILED(Hr))
{
PRINTERROR("Cannot start Q", Hr);
}
SendMsmQMessage(hSendQ, pwszMesgText, pwszMesgLabel);
Cleanup:
CloseMessageQ(hSendQ, Created);
return Hr;
}
void PrintError(char *s, HRESULT hr)
{
dprintf("Cleanup: %s (0x%X)\n", s, hr);
}