diff options
author | James Cook <james@lindenlab.com> | 2007-01-02 08:33:20 +0000 |
---|---|---|
committer | James Cook <james@lindenlab.com> | 2007-01-02 08:33:20 +0000 |
commit | 420b91db29485df39fd6e724e782c449158811cb (patch) | |
tree | b471a94563af914d3ed3edd3e856d21cb1b69945 /indra/win_crash_logger |
Print done when done.
Diffstat (limited to 'indra/win_crash_logger')
-rw-r--r-- | indra/win_crash_logger/StdAfx.cpp | 16 | ||||
-rw-r--r-- | indra/win_crash_logger/StdAfx.h | 40 | ||||
-rw-r--r-- | indra/win_crash_logger/ll_icon.ico | bin | 0 -> 2238 bytes | |||
-rw-r--r-- | indra/win_crash_logger/resource.h | 44 | ||||
-rw-r--r-- | indra/win_crash_logger/win_crash_logger.cpp | 915 | ||||
-rw-r--r-- | indra/win_crash_logger/win_crash_logger.h | 20 | ||||
-rw-r--r-- | indra/win_crash_logger/win_crash_logger.ico | bin | 0 -> 1078 bytes | |||
-rw-r--r-- | indra/win_crash_logger/win_crash_logger.rc | 207 |
8 files changed, 1242 insertions, 0 deletions
diff --git a/indra/win_crash_logger/StdAfx.cpp b/indra/win_crash_logger/StdAfx.cpp new file mode 100644 index 0000000000..541c322d90 --- /dev/null +++ b/indra/win_crash_logger/StdAfx.cpp @@ -0,0 +1,16 @@ +/** + * @file StdAfx.cpp + * @brief windows crash logger source file for includes + * + * Copyright (c) 2003-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +// stdafx.cpp : source file that includes just the standard includes +// win_crash_logger.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/indra/win_crash_logger/StdAfx.h b/indra/win_crash_logger/StdAfx.h new file mode 100644 index 0000000000..00407005e5 --- /dev/null +++ b/indra/win_crash_logger/StdAfx.h @@ -0,0 +1,40 @@ +/** + * @file StdAfx.h + * @brief standard system includes + * + * Copyright (c) 2003-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_) +#define AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + + +// Windows Header Files: +#include <windows.h> + +// C RunTime Header Files +#include <stdlib.h> +#include <malloc.h> +#include <memory.h> +#include <tchar.h> + +// Local Header Files + +// TODO: reference additional headers your program requires here + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_) diff --git a/indra/win_crash_logger/ll_icon.ico b/indra/win_crash_logger/ll_icon.ico Binary files differnew file mode 100644 index 0000000000..566346dfe3 --- /dev/null +++ b/indra/win_crash_logger/ll_icon.ico diff --git a/indra/win_crash_logger/resource.h b/indra/win_crash_logger/resource.h new file mode 100644 index 0000000000..19233df390 --- /dev/null +++ b/indra/win_crash_logger/resource.h @@ -0,0 +1,44 @@ +/** + * @file resource.h + * @brief Resources for windows crash logger + * + * Copyright (c) 2003-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by win_crash_logger.rc +// +#define IDC_MYICON 2 +#define IDD_REPORT 9 +#define IDD_WIN_CRASH_LOGGER_DIALOG 102 +#define IDD_ABOUTBOX 103 +#define IDS_APP_TITLE 103 +#define IDM_ABOUT 104 +#define IDM_EXIT 105 +#define IDS_HELLO 106 +#define IDI_WIN_CRASH_LOGGER 107 +#define IDI_SMALL 108 +#define IDC_WIN_CRASH_LOGGER 109 +#define IDR_MAINFRAME 128 +#define IDD_PROGRESS 129 +#define IDD_PREVREPORTBOX 130 +#define IDC_EDIT1 1000 +#define IDC_LOG 1004 +#define IDC_CHECK_AUTO 1006 +#define IDC_STATIC_HEADER 1007 +#define IDC_STATIC_WHATINFO 1008 +#define IDC_STATIC_MOTIVATION 1009 +#define IDC_STATIC -1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 131 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1010 +#define _APS_NEXT_SYMED_VALUE 110 +#endif +#endif diff --git a/indra/win_crash_logger/win_crash_logger.cpp b/indra/win_crash_logger/win_crash_logger.cpp new file mode 100644 index 0000000000..e9198e8ff9 --- /dev/null +++ b/indra/win_crash_logger/win_crash_logger.cpp @@ -0,0 +1,915 @@ +/** + * @file win_crash_logger.cpp + * @brief Windows crash logger implementation + * + * Copyright (c) 2003-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +// win_crash_logger.cpp : Defines the entry point for the application. +// + +#include "linden_common.h" +#include "llcontrol.h" +#include "stdafx.h" +#include "resource.h" + +#include <stdio.h> +#include <stdlib.h> +#include <direct.h> +#include <time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <wininet.h> + +#include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME +#include "llerror.h" +#include "lltimer.h" +#include "lldir.h" + +#include "llstring.h" +#include "lldxhardware.h" + +LLControlGroup gCrashSettings; // saved at end of session + +// Constants +#define MAX_LOADSTRING 100 +const char* const SETTINGS_FILE_HEADER = "version"; +const S32 SETTINGS_FILE_VERSION = 101; + +// Functions +LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); +bool handle_button_click(WORD button_id); +S32 load_crash_behavior_setting(); +bool save_crash_behavior_setting(S32 crash_behavior); +void send_crash_report(); +void write_debug(const char *str); +void write_debug(std::string& str); + +// Global Variables: +HINSTANCE hInst= NULL; // current instance +TCHAR szTitle[MAX_LOADSTRING]; // The title bar text +TCHAR szWindowClass[MAX_LOADSTRING]; // The title bar text + +LLString gUserText; // User's description of the problem +time_t gStartTime = 0; +HWND gHwndReport = NULL; // Send/Don't Send dialog +HWND gHwndProgress = NULL; // Progress window +HCURSOR gCursorArrow = NULL; +HCURSOR gCursorWait = NULL; +BOOL gFirstDialog = TRUE; // Are we currently handling the Send/Don't Send dialog? +BOOL gCrashInPreviousExec = FALSE; +FILE *gDebugFile = NULL; +LLString gUserserver; +WCHAR gProductName[512]; + +// +// Implementation +// + +// Include product name in the window caption. +void ProcessCaption(HWND hWnd) +{ + TCHAR templateText[1024]; + TCHAR finalText[2048]; + GetWindowText(hWnd, templateText, sizeof(templateText)); + swprintf(finalText, templateText, gProductName); + SetWindowText(hWnd, finalText); +} + + +// Include product name in the diaog item text. +void ProcessDlgItemText(HWND hWnd, int nIDDlgItem) +{ + TCHAR templateText[1024]; + TCHAR finalText[2048]; + GetDlgItemText(hWnd, nIDDlgItem, templateText, sizeof(templateText)); + swprintf(finalText, templateText, gProductName); + SetDlgItemText(hWnd, nIDDlgItem, finalText); +} + +int APIENTRY WinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow) +{ + llinfos << "Starting crash reporter" << llendl; + // We assume that all the logs we're looking for reside on the current drive + gDirUtilp->initAppDirs("SecondLife"); + + // Default to the product name "Second Life" (this is overridden by the -name argument) + swprintf(gProductName, L"Second Life"); + + gCrashSettings.declareS32(CRASH_BEHAVIOR_SETTING, CRASH_BEHAVIOR_ASK, "Controls behavior when viewer crashes " + "(0 = ask before sending crash report, 1 = always send crash report, 2 = never send crash report)"); + + llinfos << "Loading crash behavior setting" << llendl; + S32 crash_behavior = load_crash_behavior_setting(); + + // In Win32, we need to generate argc and argv ourselves... + // Note: GetCommandLine() returns a potentially return a LPTSTR + // which can resolve to a LPWSTR (unicode string). + // (That's why it's different from lpCmdLine which is a LPSTR.) + // We don't currently do unicode, so call the non-unicode version + // directly. + llinfos << "Processing command line" << llendl; + LPSTR cmd_line_including_exe_name = GetCommandLineA(); + + const S32 MAX_ARGS = 100; + int argc = 0; + char *argv[MAX_ARGS]; + + char *token = NULL; + if( cmd_line_including_exe_name[0] == '\"' ) + { + // Exe name is enclosed in quotes + token = strtok( cmd_line_including_exe_name, "\"" ); + argv[argc++] = token; + token = strtok( NULL, " \t," ); + } + else + { + // Exe name is not enclosed in quotes + token = strtok( cmd_line_including_exe_name, " \t," ); + } + + while( (token != NULL) && (argc < MAX_ARGS) ) + { + argv[argc++] = token; + /* Get next token: */ + if (*(token + strlen(token) + 1) == '\"') + { + token = strtok( NULL, "\""); + } + else + { + token = strtok( NULL, " \t," ); + } + } + + S32 i; + for (i=0; i<argc; i++) + { + if(!strcmp(argv[i], "-previous")) + { + llinfos << "Previous execution did not remove SecondLife.exec_marker" << llendl; + gCrashInPreviousExec = TRUE; + } + + if(!strcmp(argv[i], "-dialog")) + { + llinfos << "Show the user dialog" << llendl; + crash_behavior = CRASH_BEHAVIOR_ASK; + } + + if(!strcmp(argv[i], "-user")) + { + if ((i + 1) < argc) + { + i++; + gUserserver = argv[i]; + llinfos << "Got userserver " << gUserserver << llendl; + } + } + + if(!strcmp(argv[i], "-name")) + { + if ((i + 1) < argc) + { + i++; + + mbstowcs(gProductName, argv[i], sizeof(gProductName)); + llinfos << "Got product name " << argv[i] << llendl; + } + } + } + + // If user doesn't want to send, bail out + if (crash_behavior == CRASH_BEHAVIOR_NEVER_SEND) + { + llinfos << "Crash behavior is never_send, quitting" << llendl; + return 0; + } + + // Get the current time + time(&gStartTime); + + llinfos << "Loading dialogs" << llendl; + + // Store instance handle in our global variable + hInst = hInstance; + + // Initialize global strings + LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); + LoadString(hInstance, IDC_WIN_CRASH_LOGGER, szWindowClass, MAX_LOADSTRING); + + gCursorArrow = LoadCursor(NULL, IDC_ARROW); + gCursorWait = LoadCursor(NULL, IDC_WAIT); + + // Register a window class that will be used by our dialogs + WNDCLASS wndclass; + wndclass.style = CS_HREDRAW | CS_VREDRAW; + wndclass.lpfnWndProc = WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = DLGWINDOWEXTRA; // Required, since this is used for dialogs! + wndclass.hInstance = hInst; + wndclass.hIcon = LoadIcon(hInst, MAKEINTRESOURCE( IDI_WIN_CRASH_LOGGER ) ); + wndclass.hCursor = gCursorArrow; + wndclass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); + wndclass.lpszMenuName = NULL; + wndclass.lpszClassName = szWindowClass; + RegisterClass( &wndclass ); + + // Note: parent hwnd is 0 (the desktop). No dlg proc. See Petzold (5th ed) HexCalc example, Chapter 11, p529 + // win_crash_logger.rc has been edited by hand. + // Dialogs defined with CLASS "WIN_CRASH_LOGGER" (must be same as szWindowClass) + + gHwndProgress = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PROGRESS), 0, NULL); + ProcessCaption(gHwndProgress); + ShowWindow(gHwndProgress, SW_HIDE ); + + if (crash_behavior == CRASH_BEHAVIOR_ALWAYS_SEND) + { + ShowWindow(gHwndProgress, SW_SHOW ); + send_crash_report(); + return 0; + } + + if (crash_behavior == CRASH_BEHAVIOR_ASK) + { + gHwndReport = CreateDialog(hInst, MAKEINTRESOURCE(IDD_REPORT), 0, NULL); + + // Include the product name in the caption and various dialog items. + ProcessCaption(gHwndReport); + ProcessDlgItemText(gHwndReport, IDC_STATIC_WHATINFO); + ProcessDlgItemText(gHwndReport, IDC_STATIC_MOTIVATION); + + // Update the header to include whether or not we crashed on the last run. + WCHAR header[2048]; + if (gCrashInPreviousExec) + { + swprintf(header, L"%s appears to have crashed or frozen the last time it ran.", gProductName); + } + else + { + swprintf(header, L"%s appears to have crashed.", gProductName); + } + SetDlgItemText(gHwndReport, IDC_STATIC_HEADER, header); + ShowWindow(gHwndReport, SW_SHOW ); + + MSG msg; + while (GetMessage(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return msg.wParam; + } + else + { + llwarns << "Unknown crash behavior " << crash_behavior << llendl; + return 1; + } +} + + +LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + switch( message ) + { + case WM_CREATE: + return 0; + + case WM_COMMAND: + if( gFirstDialog ) + { + WORD button_id = LOWORD(wParam); + bool handled = handle_button_click(button_id); + if (handled) + { + return 0; + } + } + break; + + case WM_DESTROY: + // Closing the window cancels + PostQuitMessage(0); + return 0; + } + + return DefWindowProc(hwnd, message, wParam, lParam); +} + + +bool handle_button_click(WORD button_id) +{ + // Is this something other than Send or Don't Send? + if (button_id != IDOK + && button_id != IDCANCEL) + { + return false; + } + + // See if "do this next time" is checked and save state + S32 crash_behavior = CRASH_BEHAVIOR_ASK; + LRESULT result = SendDlgItemMessage(gHwndReport, IDC_CHECK_AUTO, BM_GETCHECK, 0, 0); + if (result == BST_CHECKED) + { + if (button_id == IDOK) + { + crash_behavior = CRASH_BEHAVIOR_ALWAYS_SEND; + } + else if (button_id == IDCANCEL) + { + crash_behavior = CRASH_BEHAVIOR_NEVER_SEND; + } + } + bool success = save_crash_behavior_setting(crash_behavior); + if (!success) + { + llwarns << "Failed to save crash settings" << llendl; + } + + // We're done with this dialog. + gFirstDialog = FALSE; + + // Send the crash report if requested + if (button_id == IDOK) + { + // Don't let users type anything. They believe the reports + // get read by humans, and get angry when we don't respond. JC + //WCHAR wbuffer[20000]; + //GetDlgItemText(gHwndReport, // handle to dialog box + // IDC_EDIT1, // control identifier + // wbuffer, // pointer to buffer for text + // 20000 // maximum size of string + // ); + //gUserText = wstring_to_utf8str(utf16str_to_wstring(wbuffer)).c_str(); + //llinfos << gUserText << llendl; + + // Activate and show the window. + ShowWindow(gHwndProgress, SW_SHOW); + // Try doing this second to make the progress window go frontmost. + ShowWindow(gHwndReport, SW_HIDE); + + send_crash_report(); + } + + // Quit the app + PostQuitMessage(0); + + return true; +} + + +class LLFileEncoder +{ +public: + LLFileEncoder(const char *formname, const char *filename); + + BOOL isValid() const { return mIsValid; } + LLString encodeURL(const S32 max_length = 0); +public: + BOOL mIsValid; + LLString mFilename; + LLString mFormname; + S32 mBufLength; + U8 *mBuf; +}; + +LLString encode_string(const char *formname, const LLString &str); + +void update_messages() +{ + MSG msg; + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + if (msg.message == WM_QUIT) + { + exit(0); + } + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + +void sleep_and_pump_messages( U32 seconds ) +{ + const U32 CYCLES_PER_SECOND = 10; + U32 cycles = seconds * CYCLES_PER_SECOND; + while( cycles-- ) + { + update_messages(); + ms_sleep(1000 / CYCLES_PER_SECOND); + } +} + + +void show_progress(const char* message) +{ + std::wstring msg = wstring_to_utf16str(utf8str_to_wstring(message)); + if (gHwndProgress) + { + SendDlgItemMessage(gHwndProgress, // handle to destination window + IDC_LOG, + WM_SETTEXT, // message to send + FALSE, // undo option + (LPARAM)msg.c_str()); + } +} + + +void send_crash_report() +{ + update_messages(); + show_progress("Starting up..."); + update_messages(); + + const S32 SL_MAX_SIZE = 100000; // Maximum size of the Second Life log file. + + update_messages(); + + // Lots of silly variable, replicated for each log file. + std::string db_file_name; // debug.log + std::string sl_file_name; // SecondLife.log + std::string md_file_name; // minidump (SecondLife.dmp) file name + std::string st_file_name; // stats.log file + std::string si_file_name; // settings.ini file + std::string ml_file_name; // message.log file + + LLFileEncoder *db_filep = NULL; + LLFileEncoder *sl_filep = NULL; + LLFileEncoder *st_filep = NULL; + LLFileEncoder *md_filep = NULL; + LLFileEncoder *si_filep = NULL; + LLFileEncoder *ml_filep = NULL; + + // DX hardware probe blocks, so we can't cancel during it + SetCursor(gCursorWait); + + // Need to do hardware detection before we grab the files, otherwise we don't send the debug log updates + // to the server (including the list of hardware). + update_messages(); + show_progress("Detecting hardware, please wait..."); + update_messages(); + gDXHardware.setWriteDebugFunc(write_debug); + gDXHardware.getInfo(FALSE); + update_messages(); + gDXHardware.dumpDevices(); + update_messages(); + fclose(gDebugFile); + gDebugFile = NULL; + + // At this point we're responsive enough the user could click the close button + SetCursor(gCursorArrow); + + /////////////////////////////////// + // + // We do the parsing for the debug_info file first, as that will + // give us the location of the SecondLife.log file. + // + + // Figure out the filename of the debug log + db_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log"); + db_filep = new LLFileEncoder("DB", db_file_name.c_str()); + + // Get the filename of the SecondLife.log file + char tmp_sl_name[256]; + tmp_sl_name[0] = '\0'; + + update_messages(); + show_progress("Looking for files..."); + update_messages(); + + // Look for it in the debug_info.log file + if (db_filep->isValid()) + { + sscanf((const char *)db_filep->mBuf, "SL Log: %[^\r\n]", tmp_sl_name); + } + else + { + delete db_filep; + db_filep = NULL; + } + + if (gCrashInPreviousExec) + { + // If we froze, the crash log this time around isn't useful. Use the + // old one. + sl_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.old"); + } + else if (tmp_sl_name[0]) + { + // If debug_info.log gives us a valid log filename, use that. + sl_file_name = tmp_sl_name; + llinfos << "Using log file from debug log " << sl_file_name << llendl; + } + else + { + // Figure out the filename of the default second life log + sl_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.log"); + } + + // Now we get the SecondLife.log file if it's there + sl_filep = new LLFileEncoder("SL", sl_file_name.c_str()); + if (!sl_filep->isValid()) + { + delete sl_filep; + sl_filep = NULL; + } + + update_messages(); + show_progress("Looking for stats file..."); + update_messages(); + + st_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stats.log"); + st_filep = new LLFileEncoder("ST", st_file_name.c_str()); + if (!st_filep->isValid()) + { + delete st_filep; + st_filep = NULL; + } + + si_file_name = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.ini"); + si_filep = new LLFileEncoder("SI", si_file_name.c_str()); + if (!si_filep->isValid()) + { + delete si_filep; + si_filep = NULL; + } + + // Now we get the minidump + md_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.dmp"); + md_filep = new LLFileEncoder("MD", md_file_name.c_str()); + if (!md_filep->isValid()) + { + delete md_filep; + md_filep = NULL; + } + + // Now we get the message log + ml_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"message.log"); + ml_filep = new LLFileEncoder("ML", ml_file_name.c_str()); + if (!ml_filep->isValid()) + { + delete ml_filep; + ml_filep = NULL; + } + + LLString post_data; + LLString tmp_url_buf; + + // Append the userserver + tmp_url_buf = encode_string("USER", gUserserver); + post_data += tmp_url_buf; + llinfos << "PostData:" << post_data << llendl; + + if (gCrashInPreviousExec) + { + post_data.append(1, '&'); + tmp_url_buf = encode_string("EF", "Y"); + post_data += tmp_url_buf; + } + + update_messages(); + show_progress("Encoding data"); + update_messages(); + if (db_filep) + { + post_data.append(1, '&'); + tmp_url_buf = db_filep->encodeURL(); + post_data += tmp_url_buf; + llinfos << "Sending DB log file" << llendl; + } + else + { + llinfos << "Not sending DB log file" << llendl; + } + show_progress("Encoding data."); + update_messages(); + + if (sl_filep) + { + post_data.append(1, '&'); + tmp_url_buf = sl_filep->encodeURL(SL_MAX_SIZE); + post_data += tmp_url_buf; + llinfos << "Sending SL log file" << llendl; + } + else + { + llinfos << "Not sending SL log file" << llendl; + } + show_progress("Encoding data.."); + update_messages(); + + if (st_filep) + { + post_data.append(1, '&'); + tmp_url_buf = st_filep->encodeURL(SL_MAX_SIZE); + post_data += tmp_url_buf; + llinfos << "Sending stats log file" << llendl; + } + else + { + llinfos << "Not sending stats log file" << llendl; + } + show_progress("Encoding data..."); + update_messages(); + + if (md_filep) + { + post_data.append(1, '&'); + tmp_url_buf = md_filep->encodeURL(); + post_data += tmp_url_buf; + llinfos << "Sending minidump log file" << llendl; + } + else + { + llinfos << "Not sending minidump log file" << llendl; + } + show_progress("Encoding data...."); + update_messages(); + + if (si_filep) + { + post_data.append(1, '&'); + tmp_url_buf = si_filep->encodeURL(); + post_data += tmp_url_buf; + llinfos << "Sending settings log file" << llendl; + } + else + { + llinfos << "Not sending settings.ini file" << llendl; + } + show_progress("Encoding data...."); + update_messages(); + + if (ml_filep) + { + post_data.append(1, '&'); + tmp_url_buf = ml_filep->encodeURL(SL_MAX_SIZE); + post_data += tmp_url_buf; + llinfos << "Sending message log file" << llendl; + } + else + { + llinfos << "Not sending message.log file" << llendl; + } + show_progress("Encoding data...."); + update_messages(); + + if (gUserText.size()) + { + post_data.append(1, '&'); + tmp_url_buf = encode_string("UN", gUserText); + post_data += tmp_url_buf; + } + + delete db_filep; + db_filep = NULL; + delete sl_filep; + sl_filep = NULL; + delete md_filep; + md_filep = NULL; + + // Post data to web server + const S32 BUFSIZE = 65536; + HINTERNET hinet, hsession, hrequest; + char data[BUFSIZE]; + unsigned long bytes_read; + + llinfos << "Connecting to crash report server" << llendl; + update_messages(); + show_progress("Connecting to server..."); + update_messages(); + + // Init wininet subsystem + hinet = InternetOpen(L"LindenCrashReporter", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); + if (hinet == NULL) + { + llinfos << "Couldn't open connection" << llendl; + sleep_and_pump_messages( 5 ); +// return FALSE; + } + + hsession = InternetConnect(hinet, + L"secondlife.com", + INTERNET_DEFAULT_HTTP_PORT, + NULL, + NULL, + INTERNET_SERVICE_HTTP, + NULL, + NULL); + + if (!hsession) + { + llinfos << "Couldn't talk to crash report server" << llendl; + } + + hrequest = HttpOpenRequest(hsession, L"POST", L"/cgi-bin/viewer_crash_reporter2", NULL, L"", NULL, 0, 0); + if (!hrequest) + { + llinfos << "Couldn't open crash report URL!" << llendl; + } + + llinfos << "Transmitting data" << llendl; + llinfos << "Bytes: " << (post_data.size()) << llendl; + + update_messages(); + show_progress("Transmitting data..."); + update_messages(); + + BOOL ok = HttpSendRequest(hrequest, NULL, 0, (void *)(post_data.c_str()), post_data.size()); + if (!ok) + { + llinfos << "Error posting data!" << llendl; + sleep_and_pump_messages( 5 ); + } + + llinfos << "Response from crash report server:" << llendl; + do + { + if (InternetReadFile(hrequest, data, BUFSIZE, &bytes_read)) + { + if (bytes_read == 0) + { + // If InternetFileRead returns TRUE AND bytes_read == 0 + // we've successfully downloaded the entire file + break; + } + else + { + data[bytes_read] = 0; + llinfos << data << llendl; + } + } + else + { + llinfos << "Couldn't read file!" << llendl; + sleep_and_pump_messages( 5 ); +// return FALSE; + } + } while(TRUE); + + InternetCloseHandle(hrequest); + InternetCloseHandle(hsession); + InternetCloseHandle(hinet); + update_messages(); + show_progress("Done."); + sleep_and_pump_messages( 3 ); +// return TRUE; +} + +LLFileEncoder::LLFileEncoder(const char *form_name, const char *filename) +{ + mFormname = form_name; + mFilename = filename; + mIsValid = FALSE; + mBuf = NULL; + + int res; + + llstat stat_data; + res = LLFile::stat(mFilename.c_str(), &stat_data); + if (res) + { + llwarns << "File " << mFilename << " is missing!" << llendl; + return; + } + + FILE *fp = NULL; + S32 buf_size = 0; + S32 count = 0; + while (count < 5) + { + buf_size = stat_data.st_size; + fp = LLFile::fopen(mFilename.c_str(), "rb"); + if (!fp) + { + llwarns << "Can't open file " << mFilename << ", wait for a second" << llendl; + // Couldn't open the file, wait a bit and try again + count++; + ms_sleep(1000); + } + else + { + break; + } + } + if (!fp) + { + return; + } + U8 *buf = new U8[buf_size + 1]; + fread(buf, 1, buf_size, fp); + fclose(fp); + + mBuf = buf; + mBufLength = buf_size; + + mIsValid = TRUE; +} + +LLString LLFileEncoder::encodeURL(const S32 max_length) +{ + LLString result = mFormname; + result.append(1, '='); + + S32 i = 0; + + if (max_length) + { + if (mBufLength > max_length) + { + i = mBufLength - max_length; + } + } + + S32 url_buf_size = 3*mBufLength + 1; + char *url_buf = new char[url_buf_size]; + + S32 cur_pos = 0; + for (; i < mBufLength; i++) + { + S32 byte_val = mBuf[i]; + sprintf(url_buf + cur_pos, "%%%02x", byte_val); + cur_pos += 3; + } + url_buf[i*3] = 0; + + result.append(url_buf); + delete[] url_buf; + return result; +} + +LLString encode_string(const char *formname, const LLString &str) +{ + LLString result = formname; + result.append(1, '='); + // Not using LLString because of bad performance issues + S32 buf_size = str.size(); + S32 url_buf_size = 3*str.size() + 1; + char *url_buf = new char[url_buf_size]; + + S32 cur_pos = 0; + S32 i; + for (i = 0; i < buf_size; i++) + { + sprintf(url_buf + cur_pos, "%%%02x", str[i]); + cur_pos += 3; + } + url_buf[i*3] = 0; + + result.append(url_buf); + delete[] url_buf; + return result; +} + +void write_debug(const char *str) +{ + if (!gDebugFile) + { + std::string debug_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log"); + llinfos << "Opening debug file " << debug_filename << llendl; + gDebugFile = LLFile::fopen(debug_filename.c_str(), "a+"); + if (!gDebugFile) + { + fprintf(stderr, "Couldn't open %s: debug log to stderr instead.\n", debug_filename.c_str()); + gDebugFile = stderr; + } + } + fprintf(gDebugFile, str); + fflush(gDebugFile); +} + +void write_debug(std::string& str) +{ + write_debug(str.c_str()); +} + +S32 load_crash_behavior_setting() +{ + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE); + + gCrashSettings.loadFromFile(filename); + + S32 value = gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING); + + if (value < CRASH_BEHAVIOR_ASK || CRASH_BEHAVIOR_NEVER_SEND < value) return CRASH_BEHAVIOR_ASK; + + return value; +} + +bool save_crash_behavior_setting(S32 crash_behavior) +{ + if (crash_behavior < CRASH_BEHAVIOR_ASK) return false; + if (crash_behavior > CRASH_BEHAVIOR_NEVER_SEND) return false; + + gCrashSettings.setS32(CRASH_BEHAVIOR_SETTING, crash_behavior); + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE); + + gCrashSettings.saveToFile(filename, FALSE); + + return true; +} diff --git a/indra/win_crash_logger/win_crash_logger.h b/indra/win_crash_logger/win_crash_logger.h new file mode 100644 index 0000000000..8a765cc525 --- /dev/null +++ b/indra/win_crash_logger/win_crash_logger.h @@ -0,0 +1,20 @@ +/** + * @file win_crash_logger.h + * @brief Windows crash logger project includes + * + * Copyright (c) 2003-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + + +#if !defined(AFX_WIN_CRASH_LOGGER_H__79802F4B_7C37_4F63_A2BB_0768788C3A27__INCLUDED_) +#define AFX_WIN_CRASH_LOGGER_H__79802F4B_7C37_4F63_A2BB_0768788C3A27__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "resource.h" + + +#endif // !defined(AFX_WIN_CRASH_LOGGER_H__79802F4B_7C37_4F63_A2BB_0768788C3A27__INCLUDED_) diff --git a/indra/win_crash_logger/win_crash_logger.ico b/indra/win_crash_logger/win_crash_logger.ico Binary files differnew file mode 100644 index 0000000000..386883523b --- /dev/null +++ b/indra/win_crash_logger/win_crash_logger.ico diff --git a/indra/win_crash_logger/win_crash_logger.rc b/indra/win_crash_logger/win_crash_logger.rc new file mode 100644 index 0000000000..f4c7eaa337 --- /dev/null +++ b/indra/win_crash_logger/win_crash_logger.rc @@ -0,0 +1,207 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS +#include "resource.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_WIN_CRASH_LOGGER ICON "ll_icon.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDC_WIN_CRASH_LOGGER MENU +BEGIN + POPUP "&File" + BEGIN + MENUITEM "E&xit", IDM_EXIT + END + POPUP "&Help" + BEGIN + MENUITEM "&About ...", IDM_ABOUT + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_PROGRESS DIALOG 100, 100, 186, 33 +STYLE DS_SETFONT | DS_SETFOREGROUND | WS_CAPTION | WS_SYSMENU +CAPTION "%s Crash Logger" +CLASS "WIN_CRASH_LOGGER" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Static",IDC_LOG,7,7,172,8 +END + +IDD_REPORT DIALOGEX 100, 100, 297, 125 +STYLE DS_SETFONT | DS_SETFOREGROUND | WS_CAPTION | WS_SYSMENU +CAPTION "%s Crash Logger" +CLASS "WIN_CRASH_LOGGER" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "Send",IDOK,198,104,45,15,WS_GROUP + PUSHBUTTON "Don't Send",IDCANCEL,247,104,45,15,WS_GROUP + LTEXT "%s appears to have crashed.",IDC_STATIC_HEADER,4,4,288, + 14 + LTEXT "This crash reporter collects information about your computer's hardware, operating system, and some %s logs, which are used for debugging purposes only.", + IDC_STATIC_WHATINFO,4,23,288,19,NOT WS_GROUP + CONTROL "Remember this choice",IDC_CHECK_AUTO,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,4,106,89,13 + LTEXT "Sending crash reports is the best way to help us improve the quality of %s.", + IDC_STATIC_MOTIVATION,4,38,288,8 + LTEXT "If you continue to experience this problem, please try one of the following:", + IDC_STATIC,4,57,251,8 + LTEXT "- Contact support by email at support@lindenlab.com", + IDC_STATIC,4,67,179,8 + LTEXT "- If you can log-in, please contact Live Help by using menu Help > Live Help.", + IDC_STATIC,4,87,249,8 + LTEXT "- Search the Second Life Knowledge Base at http://secondlife.com/knowledgebase/", + IDC_STATIC,4,77,281,8,SS_NOTIFY +END + +IDD_PREVREPORTBOX DIALOG 100, 100, 232, 213 +STYLE DS_SETFONT | DS_SETFOREGROUND | WS_CAPTION | WS_SYSMENU +CAPTION "%s Crash Logger" +CLASS "WIN_CRASH_LOGGER" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,131,193,45,15,WS_GROUP + EDITTEXT IDC_EDIT1,4,102,223,89,ES_MULTILINE | ES_WANTRETURN | + WS_VSCROLL + PUSHBUTTON "Cancel",IDCANCEL,181,193,45,15,WS_GROUP + LTEXT "%s appears to have crashed or frozen the last time it ran.", + IDC_STATIC,4,4,214,8 + LTEXT "This crash reporter collects information about your computer's", + IDC_STATIC,4,17,201,8 + LTEXT "hardware configuration, operating system, and some %s", + IDC_STATIC,4,25,212,8 + LTEXT "logs, all of which are used for debugging purposes only.", + IDC_STATIC,4,33,210,8 + LTEXT "In the space below, please briefly describe what you were doing", + IDC_STATIC,3,48,208,8 + LTEXT "or trying to do just prior to the crash.",IDC_STATIC,3, + 56,204,8 + LTEXT "If you don't wish to send Linden Lab a crash report, press Cancel.", + IDC_STATIC,3,90,214,8 + LTEXT "This report is NOT read by customer support. If you have billing or", + IDC_STATIC,3,68,208,8 + LTEXT "other questions, please go to: www.secondlife.com/support", + IDC_STATIC,3,76,206,8 +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +2 TEXTINCLUDE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""resource.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_PROGRESS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 26 + END + + IDD_REPORT, DIALOG + BEGIN + RIGHTMARGIN, 292 + VERTGUIDE, 4 + BOTTOMMARGIN, 119 + HORZGUIDE, 4 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_APP_TITLE "win_crash_logger" + IDS_HELLO "Hello World!" + IDC_WIN_CRASH_LOGGER "WIN_CRASH_LOGGER" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + |