diff options
| author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 | 
|---|---|---|
| committer | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 | 
| commit | 1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch) | |
| tree | ab243607f74f78200787bba5b9b88f07ef1b966f /indra/llcrashlogger | |
| parent | 6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff) | |
| parent | e1623bb276f83a43ce7a197e388720c05bdefe61 (diff) | |
Merge remote-tracking branch 'origin/main' into DRTVWR-600-maint-A
# Conflicts:
#	autobuild.xml
#	indra/cmake/CMakeLists.txt
#	indra/cmake/GoogleMock.cmake
#	indra/llaudio/llaudioengine_fmodstudio.cpp
#	indra/llaudio/llaudioengine_fmodstudio.h
#	indra/llaudio/lllistener_fmodstudio.cpp
#	indra/llaudio/lllistener_fmodstudio.h
#	indra/llaudio/llstreamingaudio_fmodstudio.cpp
#	indra/llaudio/llstreamingaudio_fmodstudio.h
#	indra/llcharacter/llmultigesture.cpp
#	indra/llcharacter/llmultigesture.h
#	indra/llimage/llimage.cpp
#	indra/llimage/llimagepng.cpp
#	indra/llimage/llimageworker.cpp
#	indra/llimage/tests/llimageworker_test.cpp
#	indra/llmessage/tests/llmockhttpclient.h
#	indra/llprimitive/llgltfmaterial.h
#	indra/llrender/llfontfreetype.cpp
#	indra/llui/llcombobox.cpp
#	indra/llui/llfolderview.cpp
#	indra/llui/llfolderviewmodel.h
#	indra/llui/lllineeditor.cpp
#	indra/llui/lllineeditor.h
#	indra/llui/lltextbase.cpp
#	indra/llui/lltextbase.h
#	indra/llui/lltexteditor.cpp
#	indra/llui/lltextvalidate.cpp
#	indra/llui/lltextvalidate.h
#	indra/llui/lluictrl.h
#	indra/llui/llview.cpp
#	indra/llwindow/llwindowmacosx.cpp
#	indra/newview/app_settings/settings.xml
#	indra/newview/llappearancemgr.cpp
#	indra/newview/llappearancemgr.h
#	indra/newview/llavatarpropertiesprocessor.cpp
#	indra/newview/llavatarpropertiesprocessor.h
#	indra/newview/llbreadcrumbview.cpp
#	indra/newview/llbreadcrumbview.h
#	indra/newview/llbreastmotion.cpp
#	indra/newview/llbreastmotion.h
#	indra/newview/llconversationmodel.h
#	indra/newview/lldensityctrl.cpp
#	indra/newview/lldensityctrl.h
#	indra/newview/llface.inl
#	indra/newview/llfloatereditsky.cpp
#	indra/newview/llfloatereditwater.cpp
#	indra/newview/llfloateremojipicker.h
#	indra/newview/llfloaterimsessiontab.cpp
#	indra/newview/llfloaterprofiletexture.cpp
#	indra/newview/llfloaterprofiletexture.h
#	indra/newview/llgesturemgr.cpp
#	indra/newview/llgesturemgr.h
#	indra/newview/llimpanel.cpp
#	indra/newview/llimpanel.h
#	indra/newview/llinventorybridge.cpp
#	indra/newview/llinventorybridge.h
#	indra/newview/llinventoryclipboard.cpp
#	indra/newview/llinventoryclipboard.h
#	indra/newview/llinventoryfunctions.cpp
#	indra/newview/llinventoryfunctions.h
#	indra/newview/llinventorygallery.cpp
#	indra/newview/lllistbrowser.cpp
#	indra/newview/lllistbrowser.h
#	indra/newview/llpanelobjectinventory.cpp
#	indra/newview/llpanelprofile.cpp
#	indra/newview/llpanelprofile.h
#	indra/newview/llpreviewgesture.cpp
#	indra/newview/llsavedsettingsglue.cpp
#	indra/newview/llsavedsettingsglue.h
#	indra/newview/lltooldraganddrop.cpp
#	indra/newview/llurllineeditorctrl.cpp
#	indra/newview/llvectorperfoptions.cpp
#	indra/newview/llvectorperfoptions.h
#	indra/newview/llviewerparceloverlay.cpp
#	indra/newview/llviewertexlayer.cpp
#	indra/newview/llviewertexturelist.cpp
#	indra/newview/macmain.h
#	indra/test/test.cpp
Diffstat (limited to 'indra/llcrashlogger')
| -rw-r--r-- | indra/llcrashlogger/llcrashlock.cpp | 150 | ||||
| -rw-r--r-- | indra/llcrashlogger/llcrashlock.h | 16 | ||||
| -rw-r--r-- | indra/llcrashlogger/llcrashlogger.cpp | 1372 | ||||
| -rw-r--r-- | indra/llcrashlogger/llcrashlogger.h | 194 | 
4 files changed, 866 insertions, 866 deletions
| diff --git a/indra/llcrashlogger/llcrashlock.cpp b/indra/llcrashlogger/llcrashlock.cpp index 18d164abde..506232ab2a 100644 --- a/indra/llcrashlogger/llcrashlock.cpp +++ b/indra/llcrashlogger/llcrashlock.cpp @@ -1,4 +1,4 @@ -/**  +/**   * @file llformat.cpp   * @date   January 2007   * @brief string formatting utility @@ -6,21 +6,21 @@   * $LicenseInfo:firstyear=2007&license=viewerlgpl$   * Second Life Viewer Source Code   * Copyright (C) 2010, Linden Research, Inc. - *  + *   * This library is free software; you can redistribute it and/or   * modify it under the terms of the GNU Lesser General Public   * License as published by the Free Software Foundation;   * version 2.1 of the License only. - *  + *   * This library is distributed in the hope that it will be useful,   * but WITHOUT ANY WARRANTY; without even the implied warranty of   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   * Lesser General Public License for more details. - *  + *   * You should have received a copy of the GNU Lesser General Public   * License along with this library; if not, write to the Free Software   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  + *   * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA   * $/LicenseInfo$   */ @@ -33,7 +33,7 @@  #include "llsd.h"  #include "llsdserialize.h"  #include "llframetimer.h" -#include <boost/filesystem.hpp>   +#include <boost/filesystem.hpp>  #include <string>  #include <iostream>  #include <stdio.h> @@ -45,49 +45,49 @@  bool LLCrashLock::isProcessAlive(U32 pid, const std::string& pname)  { -	std::wstring wpname; -	wpname = std::wstring(pname.begin(), pname.end()); - -	HANDLE snapshot; -	PROCESSENTRY32 pe32; - -	bool matched = false; - -	snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); -	if (snapshot == INVALID_HANDLE_VALUE) -	{ -		return false; -	} -	else -	{ -		pe32.dwSize = sizeof(PROCESSENTRY32); -		if (Process32First(snapshot, &pe32)) -		{ -			do { -				std::wstring wexecname = pe32.szExeFile;  -				std::string execname = std::string(wexecname.begin(), wexecname.end()); -				if (!wpname.compare(pe32.szExeFile)) -				{ -					if (pid == (U32)pe32.th32ProcessID) -					{ -						matched = true; -						break; -					} -				} -			} while (Process32Next(snapshot, &pe32)); -		} -	} -	 -	CloseHandle(snapshot); -	return matched; +    std::wstring wpname; +    wpname = std::wstring(pname.begin(), pname.end()); + +    HANDLE snapshot; +    PROCESSENTRY32 pe32; + +    bool matched = false; + +    snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); +    if (snapshot == INVALID_HANDLE_VALUE) +    { +        return false; +    } +    else +    { +        pe32.dwSize = sizeof(PROCESSENTRY32); +        if (Process32First(snapshot, &pe32)) +        { +            do { +                std::wstring wexecname = pe32.szExeFile; +                std::string execname = std::string(wexecname.begin(), wexecname.end()); +                if (!wpname.compare(pe32.szExeFile)) +                { +                    if (pid == (U32)pe32.th32ProcessID) +                    { +                        matched = true; +                        break; +                    } +                } +            } while (Process32Next(snapshot, &pe32)); +        } +    } + +    CloseHandle(snapshot); +    return matched;  }  #else   //Everyone Else  bool LLCrashLock::isProcessAlive(U32 pid, const std::string& pname)  { -    //Will boost.process ever become a reality?  +    //Will boost.process ever become a reality?      std::stringstream cmd; -     +      cmd << "pgrep '" << pname << "' | grep '^" << pid << "$'";      return (!system(cmd.str().c_str()));  } @@ -101,46 +101,46 @@ LLCrashLock::LLCrashLock() : mCleanUp(true), mWaitingPID(0)  void LLCrashLock::setCleanUp(bool cleanup)  {      mCleanUp = cleanup;  //Allow cleanup to be disabled for debugging. -}   +}  LLSD LLCrashLock::getLockFile(std::string filename)  { -	LLSD lock_sd = LLSD::emptyMap(); -     -	llifstream ifile(filename.c_str()); -     -	if (ifile.is_open()) -	{									             +    LLSD lock_sd = LLSD::emptyMap(); + +    llifstream ifile(filename.c_str()); + +    if (ifile.is_open()) +    {          LLSDSerialize::fromXML(lock_sd, ifile); -		ifile.close(); -	} +        ifile.close(); +    }      return lock_sd;  }  bool LLCrashLock::putLockFile(std::string filename, const LLSD& data) -{     +{      bool result = true;      llofstream ofile(filename.c_str()); -     -	if (!LLSDSerialize::toXML(data,ofile)) -	{ + +    if (!LLSDSerialize::toXML(data,ofile)) +    {          result=false; -	} -	ofile.close(); +    } +    ofile.close();      return result;  }  bool LLCrashLock::requestMaster( F32 timeout )  { -	if (mMaster.empty()) -	{ -		    mMaster = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, +    if (mMaster.empty()) +    { +            mMaster = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,                                              "crash_master.lock"); -	} +    }      LLSD lock_sd=getLockFile(mMaster); -     +      if (lock_sd.has("pid"))      {          mWaitingPID = lock_sd["pid"].asInteger(); @@ -150,8 +150,8 @@ bool LLCrashLock::requestMaster( F32 timeout )              return false;          }      } -     -	U32 pid = getpid(); + +    U32 pid = getpid();      lock_sd["pid"] = (LLSD::Integer)pid;      return putLockFile(mMaster,lock_sd);  } @@ -179,10 +179,10 @@ void LLCrashLock::releaseMaster()  LLSD LLCrashLock::getProcessList()  {      if (mDumpTable.empty()) -	{ -		mDumpTable= gDirUtilp->getExpandedFilename(LL_PATH_LOGS, -			                                    "crash_table.lock"); -	} +    { +        mDumpTable= gDirUtilp->getExpandedFilename(LL_PATH_LOGS, +                                                "crash_table.lock"); +    }     return getLockFile(mDumpTable);  } @@ -190,21 +190,21 @@ LLSD LLCrashLock::getProcessList()  bool LLCrashLock::fileExists(std::string filename)  {  #ifdef LL_WINDOWS // or BOOST_WINDOWS_API -	boost::filesystem::path file_path(utf8str_to_utf16str(filename)); +    boost::filesystem::path file_path(utf8str_to_utf16str(filename));  #else -	boost::filesystem::path file_path(filename); +    boost::filesystem::path file_path(filename);  #endif -	return boost::filesystem::exists(file_path); +    return boost::filesystem::exists(file_path);  }  void LLCrashLock::cleanupProcess(std::string proc_dir)  {  #ifdef LL_WINDOWS // or BOOST_WINDOWS_API -	boost::filesystem::path dir_path(utf8str_to_utf16str(proc_dir)); +    boost::filesystem::path dir_path(utf8str_to_utf16str(proc_dir));  #else -	boost::filesystem::path dir_path(proc_dir); +    boost::filesystem::path dir_path(proc_dir);  #endif -	boost::filesystem::remove_all(dir_path); +    boost::filesystem::remove_all(dir_path);  }  bool LLCrashLock::putProcessList(const LLSD& proc_sd) diff --git a/indra/llcrashlogger/llcrashlock.h b/indra/llcrashlogger/llcrashlock.h index 60b060b736..b20555b746 100644 --- a/indra/llcrashlogger/llcrashlock.h +++ b/indra/llcrashlogger/llcrashlock.h @@ -1,25 +1,25 @@ -/**  +/**   * @file llcrashlock.h   * @brief Maintainence of disk locking files for crash reporting   *   * $LicenseInfo:firstyear=2001&license=viewerlgpl$   * Second Life Viewer Source Code   * Copyright (C) 2010, Linden Research, Inc. - *  + *   * This library is free software; you can redistribute it and/or   * modify it under the terms of the GNU Lesser General Public   * License as published by the Free Software Foundation;   * version 2.1 of the License only. - *  + *   * This library is distributed in the hope that it will be useful,   * but WITHOUT ANY WARRANTY; without even the implied warranty of   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   * Lesser General Public License for more details. - *  + *   * You should have received a copy of the GNU Lesser General Public   * License along with this library; if not, write to the Free Software   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  + *   * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA   * $/LicenseInfo$   */ @@ -31,7 +31,7 @@  class LLSD; -#if !LL_WINDOWS	//For non-windows platforms. +#if !LL_WINDOWS //For non-windows platforms.  #include <signal.h>  #endif @@ -51,8 +51,8 @@ public:      LLSD getProcessList();                      //Get next process pid/dir pairs      void cleanupProcess(std::string proc_dir);               //Remove from list, clean up working dir.      bool putProcessList(const LLSD& processlist); //Write pid/dir pairs back to disk. -	static bool fileExists(std::string filename); -     +    static bool fileExists(std::string filename); +      //getters      S32 getPID(); diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp index e02894c271..46f7c40f06 100644 --- a/indra/llcrashlogger/llcrashlogger.cpp +++ b/indra/llcrashlogger/llcrashlogger.cpp @@ -1,686 +1,686 @@ - /**  -* @file llcrashlogger.cpp -* @brief Crash logger implementation -* -* $LicenseInfo:firstyear=2003&license=viewerlgpl$ -* Second Life Viewer Source Code -* Copyright (C) 2010, Linden Research, Inc. -*  -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; -* version 2.1 of the License only. -*  -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU -* Lesser General Public License for more details. -*  -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA -*  -* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA -* $/LicenseInfo$ -*/ - -#include <cstdio> -#include <cstdlib> -#include <sstream> -#include <map> - -#include "llcrashlogger.h" -#include "llcrashlock.h" -#include "linden_common.h" -#include "llstring.h" -#include "indra_constants.h"	// CRASH_BEHAVIOR_... -#include "llerror.h" -#include "llerrorcontrol.h" -#include "lltimer.h" -#include "lldir.h" -#include "llfile.h" -#include "llsdserialize.h" -#include "llproxy.h" -#include "llcorehttputil.h" -#include "llhttpsdhandler.h" -#include "httpcommon.h" -#include "httpresponse.h" -#include "llcleanup.h" - -#include <curl/curl.h> -#include <openssl/crypto.h> - -bool gBreak = false; -bool gSent = false; - -int LLCrashLogger::ssl_mutex_count = 0; -LLCoreInt::HttpMutex ** LLCrashLogger::ssl_mutex_list = NULL; - -#define CRASH_UPLOAD_RETRIES 3 /* seconds */ -#define CRASH_UPLOAD_TIMEOUT 180 /* seconds */ - -class LLCrashLoggerHandler : public LLHttpSDHandler -{ -    LOG_CLASS(LLCrashLoggerHandler); -public: -    LLCrashLoggerHandler() {} - -protected: -    virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content); -    virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status); - -}; - -void LLCrashLoggerHandler::onSuccess(LLCore::HttpResponse * response, const LLSD &content) -{ -    LL_DEBUGS("CRASHREPORT") << "Request to " << response->getRequestURL() << "succeeded" << LL_ENDL; -    gBreak = true; -    gSent = true; -} - -void LLCrashLoggerHandler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status) -{ -    LL_WARNS("CRASHREPORT") << "Request to " << response->getRequestURL() -                            << " failed: " << status.toString() << LL_ENDL; -    gBreak = true; -} - -LLCrashLogger::LLCrashLogger() : -	mCrashBehavior(CRASH_BEHAVIOR_ALWAYS_SEND), -	mCrashInPreviousExec(false), -	mCrashSettings("CrashSettings"), -	mSentCrashLogs(false), -	mCrashHost("") -{ -} - -LLCrashLogger::~LLCrashLogger() -{ - -} - -// TRIM_SIZE must remain larger than LINE_SEARCH_SIZE. -const int TRIM_SIZE = 128000; -const int LINE_SEARCH_DIST = 500; -const std::string SKIP_TEXT = "\n ...Skipping... \n"; -void trimSLLog(std::string& sllog) -{ -	if(sllog.length() > TRIM_SIZE * 2) -	{ -		std::string::iterator head = sllog.begin() + TRIM_SIZE; -		std::string::iterator tail = sllog.begin() + sllog.length() - TRIM_SIZE; -		std::string::iterator new_head = std::find(head, head - LINE_SEARCH_DIST, '\n'); -		if(new_head != head - LINE_SEARCH_DIST) -		{ -			head = new_head; -		} - -		std::string::iterator new_tail = std::find(tail, tail + LINE_SEARCH_DIST, '\n'); -		if(new_tail != tail + LINE_SEARCH_DIST) -		{ -			tail = new_tail; -		} - -		sllog.erase(head, tail); -		sllog.insert(head, SKIP_TEXT.begin(), SKIP_TEXT.end()); -	} -} - -std::string getStartupStateFromLog(std::string& sllog) -{ -	std::string startup_state = "STATE_FIRST"; -	std::string startup_token = "Startup state changing from "; - -	int index = sllog.rfind(startup_token); -	if (index < 0 || index + startup_token.length() > sllog.length()) { -		return startup_state; -	} - -	// find new line -	char cur_char = sllog[index + startup_token.length()]; -	std::string::size_type newline_loc = index + startup_token.length(); -	while(cur_char != '\n' && newline_loc < sllog.length()) -	{ -		newline_loc++; -		cur_char = sllog[newline_loc]; -	} -	 -	// get substring and find location of " to " -	std::string state_line = sllog.substr(index, newline_loc - index); -	std::string::size_type state_index = state_line.find(" to "); -	startup_state = state_line.substr(state_index + 4, state_line.length() - state_index - 4); - -	return startup_state; -} - -bool LLCrashLogger::readFromXML(LLSD& dest, const std::string& filename ) -{ -	std::string db_file_name = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,filename); -	llifstream log_file(db_file_name.c_str()); - -	// Look for it in the given file -	if (log_file.is_open()) -	{ -		LLSDSerialize::fromXML(dest, log_file); -        log_file.close(); -        return true; -    } -    else -    { -        LL_WARNS("CRASHREPORT") << "Failed to open " << db_file_name << LL_ENDL; -    } -    return false; -} - -void LLCrashLogger::mergeLogs( LLSD src_sd ) -{ -    LLSD::map_iterator iter = src_sd.beginMap(); -	LLSD::map_iterator end = src_sd.endMap(); -	for( ; iter != end; ++iter) -    { -        mDebugLog[iter->first] = iter->second; -    } -} - -bool LLCrashLogger::readMinidump(std::string minidump_path) -{ -	size_t length=0; - -	llifstream minidump_stream(minidump_path.c_str(), std::ios_base::in | std::ios_base::binary); -	if (minidump_stream.is_open()) -	{ -		minidump_stream.seekg(0, std::ios::end); -		length = (size_t)minidump_stream.tellg(); -        LL_WARNS("CRASHREPORT") << "minidump length "<< length <<LL_ENDL; -		minidump_stream.seekg(0, std::ios::beg); - -		LLSD::Binary data; -		data.resize(length); - -		minidump_stream.read(reinterpret_cast<char *>(&(data[0])),length); -		minidump_stream.close(); - -		mCrashInfo["Minidump"] = data; -	} -    else -    { -        LL_WARNS("CRASHREPORT") << "failed to open minidump "<<minidump_path<<LL_ENDL; -    } - -	return length > 0; -} - -void LLCrashLogger::gatherFiles() -{ -	updateApplication("Gathering logs..."); - -    LLSD static_sd; -    LLSD dynamic_sd; -    //if we ever want to change the endpoint we send crashes to -    //we can construct a file download ( a la feature table filename for example) -    //containing the new endpoint -    LLSD endpoint; -    std::string grid; -    std::string fqdn; -     -    bool has_logs = readFromXML( static_sd, "static_debug_info.log" ); -    has_logs |= readFromXML( dynamic_sd, "dynamic_debug_info.log" ); - -     -    if ( has_logs ) -    { -        mDebugLog = static_sd; -        mergeLogs(dynamic_sd); -		mCrashInPreviousExec = mDebugLog["CrashNotHandled"].asBoolean(); - -		mFileMap["SecondLifeLog"] = mDebugLog["SLLog"].asString(); -		mFileMap["SettingsXml"] = mDebugLog["SettingsFilename"].asString(); -        mFileMap["CrashHostUrl"] = loadCrashURLSetting(); -		if(mDebugLog.has("CAFilename")) -		{ -            LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_CA_FILE, -                LLCore::HttpRequest::GLOBAL_POLICY_ID, mDebugLog["CAFilename"].asString(), NULL); -		} -		else -		{ -            LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_CA_FILE, -                LLCore::HttpRequest::GLOBAL_POLICY_ID, gDirUtilp->getCAFile(), NULL); -		} - -		LL_INFOS("CRASHREPORT") << "Using log file from debug log " << mFileMap["SecondLifeLog"] << LL_ENDL; -		LL_INFOS("CRASHREPORT") << "Using settings file from debug log " << mFileMap["SettingsXml"] << LL_ENDL; -	} -	else -	{ -		// Figure out the filename of the second life log -        LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_CA_FILE, -            LLCore::HttpRequest::GLOBAL_POLICY_ID, gDirUtilp->getCAFile(), NULL); -         -		mFileMap["SecondLifeLog"] = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,"SecondLife.log"); -        mFileMap["SettingsXml"] = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.xml"); -	} - -    if (!gDirUtilp->fileExists(mFileMap["SecondLifeLog"]) ) //We would prefer to get this from the per-run but here's our fallback. -    { -        mFileMap["SecondLifeLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.old"); -    } - -	gatherPlatformSpecificFiles(); - - -    if ( has_logs && (mFileMap["CrashHostUrl"] != "") ) -    { -        mCrashHost = mFileMap["CrashHostUrl"]; -    } - -	//default to agni, per product -	mAltCrashHost = "http://viewercrashreport.agni.lindenlab.com/cgi-bin/viewercrashreceiver.py"; - -	mCrashInfo["DebugLog"] = mDebugLog; -	mFileMap["StatsLog"] = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,"stats.log"); -	 -	updateApplication("Encoding files..."); - -	for(std::map<std::string, std::string>::iterator itr = mFileMap.begin(); itr != mFileMap.end(); ++itr) -	{ -        std::string file = (*itr).second; -        if (!file.empty()) -        { -            LL_DEBUGS("CRASHREPORT") << "trying to read " << itr->first << ": " << file << LL_ENDL; -            llifstream f(file.c_str()); -            if(f.is_open()) -            { -                std::stringstream s; -                s << f.rdbuf(); - -                std::string crash_info = s.str(); -                if(itr->first == "SecondLifeLog") -                { -                    if(!mCrashInfo["DebugLog"].has("StartupState")) -                    { -                        mCrashInfo["DebugLog"]["StartupState"] = getStartupStateFromLog(crash_info); -                    } -                    trimSLLog(crash_info); -                } - -                mCrashInfo[(*itr).first] = LLStringFn::strip_invalid_xml(rawstr_to_utf8(crash_info)); -            } -            else -            { -                LL_WARNS("CRASHREPORT") << "Failed to open file " << file << LL_ENDL; -            } -        } -        else -        { -            LL_DEBUGS("CRASHREPORT") << "empty file in list for " << itr->first << LL_ENDL; -        } -	} -	 -	std::string minidump_path; -	// Add minidump as binary. -    bool has_minidump = mDebugLog.has("MinidumpPath"); -     -	if (has_minidump) -	{ -		minidump_path = mDebugLog["MinidumpPath"].asString(); -		has_minidump = readMinidump(minidump_path); -	} -    else -    { -        LL_WARNS("CRASHREPORT") << "DebugLog does not have MinidumpPath" << LL_ENDL; -    } - -    if (!has_minidump)  //Viewer was probably so hosed it couldn't write remaining data.  Try brute force. -    { -        //Look for a filename at least 30 characters long in the dump dir which contains the characters MDMP as the first 4 characters in the file. -        typedef std::vector<std::string> vec; -        std::string pathname = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,""); -        LL_WARNS("CRASHREPORT") << "Searching for minidump in " << pathname << LL_ENDL; -        vec file_vec = gDirUtilp->getFilesInDir(pathname); -        for(vec::const_iterator iter=file_vec.begin(); !has_minidump && iter!=file_vec.end(); ++iter) -        { -            if ( ( iter->length() > 30 ) && (iter->rfind(".dmp") == (iter->length()-4) ) ) -            { -                std::string fullname = pathname + *iter; -                llifstream fdat(fullname.c_str(), std::ifstream::binary); -                if (fdat) -                { -                    char buf[5]; -                    fdat.read(buf,4); -                    fdat.close();   -                    if (!strncmp(buf,"MDMP",4)) -                    { -                        minidump_path = *iter; -                        has_minidump = readMinidump(fullname); -						mDebugLog["MinidumpPath"] = fullname; -                    } -                    else -                    { -                        LL_DEBUGS("CRASHREPORT") << "MDMP not found in " << fullname << LL_ENDL; -                    } -                } -                else -                { -                    LL_DEBUGS("CRASHREPORT") << "failed to open " << fullname << LL_ENDL; -                } -            } -            else -            { -                LL_DEBUGS("CRASHREPORT") << "Name does not match minidump name pattern " << *iter << LL_ENDL; -            }             -        } -    } -    else -    { -        LL_WARNS("CRASHREPORT") << "readMinidump returned no minidump" << LL_ENDL; -    } -} - -LLSD LLCrashLogger::constructPostData() -{ -	return mCrashInfo; -} - -const char* const CRASH_SETTINGS_FILE = "settings_crash_behavior.xml"; - -std::string LLCrashLogger::loadCrashURLSetting() -{ - -	// First check user_settings (in the user's home dir) -	std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE); -	if (! mCrashSettings.loadFromFile(filename)) -	{ -		// Next check app_settings (in the SL program dir) -		std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, CRASH_SETTINGS_FILE); -		mCrashSettings.loadFromFile(filename); -	} - -    if (! mCrashSettings.controlExists("CrashHostUrl")) -    { -        return ""; -    } -    else -    { -        return mCrashSettings.getString("CrashHostUrl"); -    } -} - -bool LLCrashLogger::runCrashLogPost(std::string host, LLSD data, std::string msg, int retries, int timeout) -{ -    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); -    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); - -    httpOpts->setTimeout(timeout); -    httpOpts->setSSLVerifyPeer(false); - -	for(int i = 0; i < retries; ++i) -	{ -		updateApplication(llformat("%s, try %d...", msg.c_str(), i+1)); - -        LL_INFOS("CRASHREPORT") << "POST crash data to " << host << LL_ENDL; -        LLCore::HttpHandle handle = LLCoreHttpUtil::requestPostWithLLSD(httpRequest.get(), LLCore::HttpRequest::DEFAULT_POLICY_ID, -            host, data, httpOpts, LLCore::HttpHeaders::ptr_t(), LLCore::HttpHandler::ptr_t(new LLCrashLoggerHandler)); - -        if (handle == LLCORE_HTTP_HANDLE_INVALID) -        { -            LLCore::HttpStatus status = httpRequest->getStatus(); -            LL_WARNS("CRASHREPORT") << "Request POST failed to " << host << " with status of [" << -                status.getType() << "]\"" << status.toString() << "\"" << LL_ENDL; -            return false; -        } - -        while(!gBreak) -        { -            ms_sleep(250); -            updateApplication(); // No new message, just pump the IO -            httpRequest->update(0L); -        } -		if(gSent) -		{ -			return gSent; -		} - -        LL_WARNS("CRASHREPORT") << "Failed to send crash report to \"" << host << "\"" << LL_ENDL; -	} -	return gSent; -} - -bool LLCrashLogger::sendCrashLog(std::string dump_dir) -{ - -    gDirUtilp->setDumpDir( dump_dir ); -     -    std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, -                                                           "SecondLifeCrashReport"); -    std::string report_file = dump_path + ".log"; - -    LL_DEBUGS("CRASHREPORT") << "sending " << report_file << LL_ENDL; - -	gatherFiles(); -     -	LLSD post_data; -	post_data = constructPostData(); -     -	updateApplication("Sending reports..."); - -	llofstream out_file(report_file.c_str()); -	LLSDSerialize::toPrettyXML(post_data, out_file); -    out_file.flush(); -	out_file.close(); -     -	bool sent = false; -     -    if(mCrashHost != "") -	{ -        LL_WARNS("CRASHREPORT") << "Sending crash data to server from CrashHostUrl '" << mCrashHost << "'" << LL_ENDL; -         -        std::string msg = "Using override crash server... "; -        msg = msg+mCrashHost.c_str(); -        updateApplication(msg.c_str()); -         -		sent = runCrashLogPost(mCrashHost, post_data, std::string("Sending to server"), CRASH_UPLOAD_RETRIES, CRASH_UPLOAD_TIMEOUT); -	} -     -	if(!sent) -	{ -        updateApplication("Using default server..."); -		sent = runCrashLogPost(mAltCrashHost, post_data, std::string("Sending to default server"), CRASH_UPLOAD_RETRIES, CRASH_UPLOAD_TIMEOUT); -	} -     -	mSentCrashLogs = sent; -     -	return sent; -} - -bool LLCrashLogger::sendCrashLogs() -{ -    LLSD locks = mKeyMaster.getProcessList(); -    LLSD newlocks = LLSD::emptyArray(); - -	LLSD opts = getOptionData(PRIORITY_COMMAND_LINE); -    LLSD rec; - -	if ( opts.has("pid") && opts.has("dumpdir") && opts.has("procname") ) -    { -        rec["pid"]=opts["pid"]; -        rec["dumpdir"]=opts["dumpdir"]; -        rec["procname"]=opts["procname"]; -    } -	 -    if (locks.isArray()) -    { -        for (LLSD::array_iterator lock=locks.beginArray(); -             lock !=locks.endArray(); -             ++lock) -        { -            if ( (*lock).has("pid") && (*lock).has("dumpdir") && (*lock).has("procname") ) -            { -                if ( mKeyMaster.isProcessAlive( (*lock)["pid"].asInteger(), (*lock)["procname"].asString() ) ) -                { -                    newlocks.append(*lock); -                } -                else -                { -					//TODO:  This is a hack but I didn't want to include boost in another file or retest everything related to lldir  -                    if (LLCrashLock::fileExists((*lock)["dumpdir"].asString())) -                    { -                        //the viewer cleans up the log directory on clean shutdown -                        //but is ignorant of the locking table.  -                        if (!sendCrashLog((*lock)["dumpdir"].asString())) -                        { -                            newlocks.append(*lock);    //Failed to send log so don't delete it. -                        } -                        else -                        { -                            mKeyMaster.cleanupProcess((*lock)["dumpdir"].asString()); -                        } -                    } -				} -            } -            else -            { -                LL_INFOS() << "Discarding corrupted entry from lock table." << LL_ENDL; -            } -        } -    } - -    if (rec) -    { -        newlocks.append(rec); -    } -     -    mKeyMaster.putProcessList(newlocks); -    return true; -} - -void LLCrashLogger::updateApplication(const std::string& message) -{ -	if (!message.empty()) LL_INFOS("CRASHREPORT") << message << LL_ENDL; -} - -bool LLCrashLogger::init() -{ -    LL_DEBUGS("CRASHREPORT") << LL_ENDL; -     -    LLCore::LLHttp::initialize(); - -	// We assume that all the logs we're looking for reside on the current drive -	gDirUtilp->initAppDirs("SecondLife"); - -	LLError::initForApplication(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""), gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); - -	// Default to the product name "Second Life" (this is overridden by the -name argument) -	mProductName = "Second Life"; - -	// Rename current log file to ".old" -	std::string old_log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "crashreport.log.old"); -	std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "crashreport.log"); - -#if LL_WINDOWS -	LLAPRFile::remove(old_log_file); -#endif  - -	LLFile::rename(log_file.c_str(), old_log_file.c_str()); -     -	// Set the log file to crashreport.log -	LLError::logToFile(log_file);  //NOTE:  Until this line, LL_INFOS LL_WARNS, etc are blown to the ether.  - -    LL_INFOS("CRASHREPORT") << "Crash reporter file rotation complete." << LL_ENDL; - -    // Handle locking -    bool locked = mKeyMaster.requestMaster();  //Request master locking file.  wait time is defaulted to 300S -     -    while (!locked && mKeyMaster.isWaiting()) -    { -		LL_INFOS("CRASHREPORT") << "Waiting for lock." << LL_ENDL; -#if LL_WINDOWS -		Sleep(1000); -#else -        ::sleep(1); -#endif  -        locked = mKeyMaster.checkMaster(); -    } -     -    if (!locked) -    { -        LL_WARNS("CRASHREPORT") << "Unable to get master lock.  Another crash reporter may be hung." << LL_ENDL; -        return false; -    } - -    mCrashSettings.declareS32("CrashSubmitBehavior", CRASH_BEHAVIOR_ALWAYS_SEND, -							  "Controls behavior when viewer crashes " -							  "(0 = ask before sending crash report, " -							  "1 = always send crash report, " -							  "2 = never send crash report)"); -     -    init_curl(); -    LLCore::HttpRequest::createService(); -    LLCore::HttpRequest::startThread(); - -	return true; -} - -// For cleanup code common to all platforms. -void LLCrashLogger::commonCleanup() -{ -    term_curl(); -	LLError::logToFile("");   //close crashreport.log -	SUBSYSTEM_CLEANUP(LLProxy); -} - -void LLCrashLogger::init_curl() -{ -    curl_global_init(CURL_GLOBAL_ALL); - -    ssl_mutex_count = CRYPTO_num_locks(); -    if (ssl_mutex_count > 0) -    { -        ssl_mutex_list = new LLCoreInt::HttpMutex *[ssl_mutex_count]; - -        for (int i(0); i < ssl_mutex_count; ++i) -        { -            ssl_mutex_list[i] = new LLCoreInt::HttpMutex; -        } - -        CRYPTO_set_locking_callback(ssl_locking_callback); -        CRYPTO_THREADID_set_callback(ssl_thread_id_callback); -    } -} - - -void LLCrashLogger::term_curl() -{ -    CRYPTO_set_locking_callback(NULL); -    for (int i(0); i < ssl_mutex_count; ++i) -    { -        delete ssl_mutex_list[i]; -    } -    delete[] ssl_mutex_list; -} - - -void LLCrashLogger::ssl_thread_id_callback(CRYPTO_THREADID* pthreadid) -{ -#if LL_WINDOWS -    CRYPTO_THREADID_set_pointer(pthreadid, GetCurrentThread()); -#else -    CRYPTO_THREADID_set_pointer(pthreadid, reinterpret_cast<void*>(pthread_self())); -#endif -} - - -void LLCrashLogger::ssl_locking_callback(int mode, int type, const char * /* file */, int /* line */) -{ -    if (type >= 0 && type < ssl_mutex_count) -    { -        if (mode & CRYPTO_LOCK) -        { -            ssl_mutex_list[type]->lock(); -        } -        else -        { -            ssl_mutex_list[type]->unlock(); -        } -    } -} - + /**
 +* @file llcrashlogger.cpp
 +* @brief Crash logger implementation
 +*
 +* $LicenseInfo:firstyear=2003&license=viewerlgpl$
 +* Second Life Viewer Source Code
 +* Copyright (C) 2010, Linden Research, Inc.
 +*
 +* This library is free software; you can redistribute it and/or
 +* modify it under the terms of the GNU Lesser General Public
 +* License as published by the Free Software Foundation;
 +* version 2.1 of the License only.
 +*
 +* This library is distributed in the hope that it will be useful,
 +* but WITHOUT ANY WARRANTY; without even the implied warranty of
 +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 +* Lesser General Public License for more details.
 +*
 +* You should have received a copy of the GNU Lesser General Public
 +* License along with this library; if not, write to the Free Software
 +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 +*
 +* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 +* $/LicenseInfo$
 +*/
 +
 +#include <cstdio>
 +#include <cstdlib>
 +#include <sstream>
 +#include <map>
 +
 +#include "llcrashlogger.h"
 +#include "llcrashlock.h"
 +#include "linden_common.h"
 +#include "llstring.h"
 +#include "indra_constants.h"    // CRASH_BEHAVIOR_...
 +#include "llerror.h"
 +#include "llerrorcontrol.h"
 +#include "lltimer.h"
 +#include "lldir.h"
 +#include "llfile.h"
 +#include "llsdserialize.h"
 +#include "llproxy.h"
 +#include "llcorehttputil.h"
 +#include "llhttpsdhandler.h"
 +#include "httpcommon.h"
 +#include "httpresponse.h"
 +#include "llcleanup.h"
 +
 +#include <curl/curl.h>
 +#include <openssl/crypto.h>
 +
 +bool gBreak = false;
 +bool gSent = false;
 +
 +int LLCrashLogger::ssl_mutex_count = 0;
 +LLCoreInt::HttpMutex ** LLCrashLogger::ssl_mutex_list = NULL;
 +
 +#define CRASH_UPLOAD_RETRIES 3 /* seconds */
 +#define CRASH_UPLOAD_TIMEOUT 180 /* seconds */
 +
 +class LLCrashLoggerHandler : public LLHttpSDHandler
 +{
 +    LOG_CLASS(LLCrashLoggerHandler);
 +public:
 +    LLCrashLoggerHandler() {}
 +
 +protected:
 +    virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content);
 +    virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status);
 +
 +};
 +
 +void LLCrashLoggerHandler::onSuccess(LLCore::HttpResponse * response, const LLSD &content)
 +{
 +    LL_DEBUGS("CRASHREPORT") << "Request to " << response->getRequestURL() << "succeeded" << LL_ENDL;
 +    gBreak = true;
 +    gSent = true;
 +}
 +
 +void LLCrashLoggerHandler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status)
 +{
 +    LL_WARNS("CRASHREPORT") << "Request to " << response->getRequestURL()
 +                            << " failed: " << status.toString() << LL_ENDL;
 +    gBreak = true;
 +}
 +
 +LLCrashLogger::LLCrashLogger() :
 +    mCrashBehavior(CRASH_BEHAVIOR_ALWAYS_SEND),
 +    mCrashInPreviousExec(false),
 +    mCrashSettings("CrashSettings"),
 +    mSentCrashLogs(false),
 +    mCrashHost("")
 +{
 +}
 +
 +LLCrashLogger::~LLCrashLogger()
 +{
 +
 +}
 +
 +// TRIM_SIZE must remain larger than LINE_SEARCH_SIZE.
 +const int TRIM_SIZE = 128000;
 +const int LINE_SEARCH_DIST = 500;
 +const std::string SKIP_TEXT = "\n ...Skipping... \n";
 +void trimSLLog(std::string& sllog)
 +{
 +    if(sllog.length() > TRIM_SIZE * 2)
 +    {
 +        std::string::iterator head = sllog.begin() + TRIM_SIZE;
 +        std::string::iterator tail = sllog.begin() + sllog.length() - TRIM_SIZE;
 +        std::string::iterator new_head = std::find(head, head - LINE_SEARCH_DIST, '\n');
 +        if(new_head != head - LINE_SEARCH_DIST)
 +        {
 +            head = new_head;
 +        }
 +
 +        std::string::iterator new_tail = std::find(tail, tail + LINE_SEARCH_DIST, '\n');
 +        if(new_tail != tail + LINE_SEARCH_DIST)
 +        {
 +            tail = new_tail;
 +        }
 +
 +        sllog.erase(head, tail);
 +        sllog.insert(head, SKIP_TEXT.begin(), SKIP_TEXT.end());
 +    }
 +}
 +
 +std::string getStartupStateFromLog(std::string& sllog)
 +{
 +    std::string startup_state = "STATE_FIRST";
 +    std::string startup_token = "Startup state changing from ";
 +
 +    int index = sllog.rfind(startup_token);
 +    if (index < 0 || index + startup_token.length() > sllog.length()) {
 +        return startup_state;
 +    }
 +
 +    // find new line
 +    char cur_char = sllog[index + startup_token.length()];
 +    std::string::size_type newline_loc = index + startup_token.length();
 +    while(cur_char != '\n' && newline_loc < sllog.length())
 +    {
 +        newline_loc++;
 +        cur_char = sllog[newline_loc];
 +    }
 +
 +    // get substring and find location of " to "
 +    std::string state_line = sllog.substr(index, newline_loc - index);
 +    std::string::size_type state_index = state_line.find(" to ");
 +    startup_state = state_line.substr(state_index + 4, state_line.length() - state_index - 4);
 +
 +    return startup_state;
 +}
 +
 +bool LLCrashLogger::readFromXML(LLSD& dest, const std::string& filename )
 +{
 +    std::string db_file_name = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,filename);
 +    llifstream log_file(db_file_name.c_str());
 +
 +    // Look for it in the given file
 +    if (log_file.is_open())
 +    {
 +        LLSDSerialize::fromXML(dest, log_file);
 +        log_file.close();
 +        return true;
 +    }
 +    else
 +    {
 +        LL_WARNS("CRASHREPORT") << "Failed to open " << db_file_name << LL_ENDL;
 +    }
 +    return false;
 +}
 +
 +void LLCrashLogger::mergeLogs( LLSD src_sd )
 +{
 +    LLSD::map_iterator iter = src_sd.beginMap();
 +    LLSD::map_iterator end = src_sd.endMap();
 +    for( ; iter != end; ++iter)
 +    {
 +        mDebugLog[iter->first] = iter->second;
 +    }
 +}
 +
 +bool LLCrashLogger::readMinidump(std::string minidump_path)
 +{
 +    size_t length=0;
 +
 +    llifstream minidump_stream(minidump_path.c_str(), std::ios_base::in | std::ios_base::binary);
 +    if (minidump_stream.is_open())
 +    {
 +        minidump_stream.seekg(0, std::ios::end);
 +        length = (size_t)minidump_stream.tellg();
 +        LL_WARNS("CRASHREPORT") << "minidump length "<< length <<LL_ENDL;
 +        minidump_stream.seekg(0, std::ios::beg);
 +
 +        LLSD::Binary data;
 +        data.resize(length);
 +
 +        minidump_stream.read(reinterpret_cast<char *>(&(data[0])),length);
 +        minidump_stream.close();
 +
 +        mCrashInfo["Minidump"] = data;
 +    }
 +    else
 +    {
 +        LL_WARNS("CRASHREPORT") << "failed to open minidump "<<minidump_path<<LL_ENDL;
 +    }
 +
 +    return length > 0;
 +}
 +
 +void LLCrashLogger::gatherFiles()
 +{
 +    updateApplication("Gathering logs...");
 +
 +    LLSD static_sd;
 +    LLSD dynamic_sd;
 +    //if we ever want to change the endpoint we send crashes to
 +    //we can construct a file download ( a la feature table filename for example)
 +    //containing the new endpoint
 +    LLSD endpoint;
 +    std::string grid;
 +    std::string fqdn;
 +
 +    bool has_logs = readFromXML( static_sd, "static_debug_info.log" );
 +    has_logs |= readFromXML( dynamic_sd, "dynamic_debug_info.log" );
 +
 +
 +    if ( has_logs )
 +    {
 +        mDebugLog = static_sd;
 +        mergeLogs(dynamic_sd);
 +        mCrashInPreviousExec = mDebugLog["CrashNotHandled"].asBoolean();
 +
 +        mFileMap["SecondLifeLog"] = mDebugLog["SLLog"].asString();
 +        mFileMap["SettingsXml"] = mDebugLog["SettingsFilename"].asString();
 +        mFileMap["CrashHostUrl"] = loadCrashURLSetting();
 +        if(mDebugLog.has("CAFilename"))
 +        {
 +            LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_CA_FILE,
 +                LLCore::HttpRequest::GLOBAL_POLICY_ID, mDebugLog["CAFilename"].asString(), NULL);
 +        }
 +        else
 +        {
 +            LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_CA_FILE,
 +                LLCore::HttpRequest::GLOBAL_POLICY_ID, gDirUtilp->getCAFile(), NULL);
 +        }
 +
 +        LL_INFOS("CRASHREPORT") << "Using log file from debug log " << mFileMap["SecondLifeLog"] << LL_ENDL;
 +        LL_INFOS("CRASHREPORT") << "Using settings file from debug log " << mFileMap["SettingsXml"] << LL_ENDL;
 +    }
 +    else
 +    {
 +        // Figure out the filename of the second life log
 +        LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_CA_FILE,
 +            LLCore::HttpRequest::GLOBAL_POLICY_ID, gDirUtilp->getCAFile(), NULL);
 +
 +        mFileMap["SecondLifeLog"] = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,"SecondLife.log");
 +        mFileMap["SettingsXml"] = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.xml");
 +    }
 +
 +    if (!gDirUtilp->fileExists(mFileMap["SecondLifeLog"]) ) //We would prefer to get this from the per-run but here's our fallback.
 +    {
 +        mFileMap["SecondLifeLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.old");
 +    }
 +
 +    gatherPlatformSpecificFiles();
 +
 +
 +    if ( has_logs && (mFileMap["CrashHostUrl"] != "") )
 +    {
 +        mCrashHost = mFileMap["CrashHostUrl"];
 +    }
 +
 +    //default to agni, per product
 +    mAltCrashHost = "http://viewercrashreport.agni.lindenlab.com/cgi-bin/viewercrashreceiver.py";
 +
 +    mCrashInfo["DebugLog"] = mDebugLog;
 +    mFileMap["StatsLog"] = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,"stats.log");
 +
 +    updateApplication("Encoding files...");
 +
 +    for(std::map<std::string, std::string>::iterator itr = mFileMap.begin(); itr != mFileMap.end(); ++itr)
 +    {
 +        std::string file = (*itr).second;
 +        if (!file.empty())
 +        {
 +            LL_DEBUGS("CRASHREPORT") << "trying to read " << itr->first << ": " << file << LL_ENDL;
 +            llifstream f(file.c_str());
 +            if(f.is_open())
 +            {
 +                std::stringstream s;
 +                s << f.rdbuf();
 +
 +                std::string crash_info = s.str();
 +                if(itr->first == "SecondLifeLog")
 +                {
 +                    if(!mCrashInfo["DebugLog"].has("StartupState"))
 +                    {
 +                        mCrashInfo["DebugLog"]["StartupState"] = getStartupStateFromLog(crash_info);
 +                    }
 +                    trimSLLog(crash_info);
 +                }
 +
 +                mCrashInfo[(*itr).first] = LLStringFn::strip_invalid_xml(rawstr_to_utf8(crash_info));
 +            }
 +            else
 +            {
 +                LL_WARNS("CRASHREPORT") << "Failed to open file " << file << LL_ENDL;
 +            }
 +        }
 +        else
 +        {
 +            LL_DEBUGS("CRASHREPORT") << "empty file in list for " << itr->first << LL_ENDL;
 +        }
 +    }
 +
 +    std::string minidump_path;
 +    // Add minidump as binary.
 +    bool has_minidump = mDebugLog.has("MinidumpPath");
 +
 +    if (has_minidump)
 +    {
 +        minidump_path = mDebugLog["MinidumpPath"].asString();
 +        has_minidump = readMinidump(minidump_path);
 +    }
 +    else
 +    {
 +        LL_WARNS("CRASHREPORT") << "DebugLog does not have MinidumpPath" << LL_ENDL;
 +    }
 +
 +    if (!has_minidump)  //Viewer was probably so hosed it couldn't write remaining data.  Try brute force.
 +    {
 +        //Look for a filename at least 30 characters long in the dump dir which contains the characters MDMP as the first 4 characters in the file.
 +        typedef std::vector<std::string> vec;
 +        std::string pathname = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,"");
 +        LL_WARNS("CRASHREPORT") << "Searching for minidump in " << pathname << LL_ENDL;
 +        vec file_vec = gDirUtilp->getFilesInDir(pathname);
 +        for(vec::const_iterator iter=file_vec.begin(); !has_minidump && iter!=file_vec.end(); ++iter)
 +        {
 +            if ( ( iter->length() > 30 ) && (iter->rfind(".dmp") == (iter->length()-4) ) )
 +            {
 +                std::string fullname = pathname + *iter;
 +                llifstream fdat(fullname.c_str(), std::ifstream::binary);
 +                if (fdat)
 +                {
 +                    char buf[5];
 +                    fdat.read(buf,4);
 +                    fdat.close();
 +                    if (!strncmp(buf,"MDMP",4))
 +                    {
 +                        minidump_path = *iter;
 +                        has_minidump = readMinidump(fullname);
 +                        mDebugLog["MinidumpPath"] = fullname;
 +                    }
 +                    else
 +                    {
 +                        LL_DEBUGS("CRASHREPORT") << "MDMP not found in " << fullname << LL_ENDL;
 +                    }
 +                }
 +                else
 +                {
 +                    LL_DEBUGS("CRASHREPORT") << "failed to open " << fullname << LL_ENDL;
 +                }
 +            }
 +            else
 +            {
 +                LL_DEBUGS("CRASHREPORT") << "Name does not match minidump name pattern " << *iter << LL_ENDL;
 +            }
 +        }
 +    }
 +    else
 +    {
 +        LL_WARNS("CRASHREPORT") << "readMinidump returned no minidump" << LL_ENDL;
 +    }
 +}
 +
 +LLSD LLCrashLogger::constructPostData()
 +{
 +    return mCrashInfo;
 +}
 +
 +const char* const CRASH_SETTINGS_FILE = "settings_crash_behavior.xml";
 +
 +std::string LLCrashLogger::loadCrashURLSetting()
 +{
 +
 +    // First check user_settings (in the user's home dir)
 +    std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE);
 +    if (! mCrashSettings.loadFromFile(filename))
 +    {
 +        // Next check app_settings (in the SL program dir)
 +        std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, CRASH_SETTINGS_FILE);
 +        mCrashSettings.loadFromFile(filename);
 +    }
 +
 +    if (! mCrashSettings.controlExists("CrashHostUrl"))
 +    {
 +        return "";
 +    }
 +    else
 +    {
 +        return mCrashSettings.getString("CrashHostUrl");
 +    }
 +}
 +
 +bool LLCrashLogger::runCrashLogPost(std::string host, LLSD data, std::string msg, int retries, int timeout)
 +{
 +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
 +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
 +
 +    httpOpts->setTimeout(timeout);
 +    httpOpts->setSSLVerifyPeer(false);
 +
 +    for(int i = 0; i < retries; ++i)
 +    {
 +        updateApplication(llformat("%s, try %d...", msg.c_str(), i+1));
 +
 +        LL_INFOS("CRASHREPORT") << "POST crash data to " << host << LL_ENDL;
 +        LLCore::HttpHandle handle = LLCoreHttpUtil::requestPostWithLLSD(httpRequest.get(), LLCore::HttpRequest::DEFAULT_POLICY_ID,
 +            host, data, httpOpts, LLCore::HttpHeaders::ptr_t(), LLCore::HttpHandler::ptr_t(new LLCrashLoggerHandler));
 +
 +        if (handle == LLCORE_HTTP_HANDLE_INVALID)
 +        {
 +            LLCore::HttpStatus status = httpRequest->getStatus();
 +            LL_WARNS("CRASHREPORT") << "Request POST failed to " << host << " with status of [" <<
 +                status.getType() << "]\"" << status.toString() << "\"" << LL_ENDL;
 +            return false;
 +        }
 +
 +        while(!gBreak)
 +        {
 +            ms_sleep(250);
 +            updateApplication(); // No new message, just pump the IO
 +            httpRequest->update(0L);
 +        }
 +        if(gSent)
 +        {
 +            return gSent;
 +        }
 +
 +        LL_WARNS("CRASHREPORT") << "Failed to send crash report to \"" << host << "\"" << LL_ENDL;
 +    }
 +    return gSent;
 +}
 +
 +bool LLCrashLogger::sendCrashLog(std::string dump_dir)
 +{
 +
 +    gDirUtilp->setDumpDir( dump_dir );
 +
 +    std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
 +                                                           "SecondLifeCrashReport");
 +    std::string report_file = dump_path + ".log";
 +
 +    LL_DEBUGS("CRASHREPORT") << "sending " << report_file << LL_ENDL;
 +
 +    gatherFiles();
 +
 +    LLSD post_data;
 +    post_data = constructPostData();
 +
 +    updateApplication("Sending reports...");
 +
 +    llofstream out_file(report_file.c_str());
 +    LLSDSerialize::toPrettyXML(post_data, out_file);
 +    out_file.flush();
 +    out_file.close();
 +
 +    bool sent = false;
 +
 +    if(mCrashHost != "")
 +    {
 +        LL_WARNS("CRASHREPORT") << "Sending crash data to server from CrashHostUrl '" << mCrashHost << "'" << LL_ENDL;
 +
 +        std::string msg = "Using override crash server... ";
 +        msg = msg+mCrashHost.c_str();
 +        updateApplication(msg.c_str());
 +
 +        sent = runCrashLogPost(mCrashHost, post_data, std::string("Sending to server"), CRASH_UPLOAD_RETRIES, CRASH_UPLOAD_TIMEOUT);
 +    }
 +
 +    if(!sent)
 +    {
 +        updateApplication("Using default server...");
 +        sent = runCrashLogPost(mAltCrashHost, post_data, std::string("Sending to default server"), CRASH_UPLOAD_RETRIES, CRASH_UPLOAD_TIMEOUT);
 +    }
 +
 +    mSentCrashLogs = sent;
 +
 +    return sent;
 +}
 +
 +bool LLCrashLogger::sendCrashLogs()
 +{
 +    LLSD locks = mKeyMaster.getProcessList();
 +    LLSD newlocks = LLSD::emptyArray();
 +
 +    LLSD opts = getOptionData(PRIORITY_COMMAND_LINE);
 +    LLSD rec;
 +
 +    if ( opts.has("pid") && opts.has("dumpdir") && opts.has("procname") )
 +    {
 +        rec["pid"]=opts["pid"];
 +        rec["dumpdir"]=opts["dumpdir"];
 +        rec["procname"]=opts["procname"];
 +    }
 +
 +    if (locks.isArray())
 +    {
 +        for (LLSD::array_iterator lock=locks.beginArray();
 +             lock !=locks.endArray();
 +             ++lock)
 +        {
 +            if ( (*lock).has("pid") && (*lock).has("dumpdir") && (*lock).has("procname") )
 +            {
 +                if ( mKeyMaster.isProcessAlive( (*lock)["pid"].asInteger(), (*lock)["procname"].asString() ) )
 +                {
 +                    newlocks.append(*lock);
 +                }
 +                else
 +                {
 +                    //TODO:  This is a hack but I didn't want to include boost in another file or retest everything related to lldir
 +                    if (LLCrashLock::fileExists((*lock)["dumpdir"].asString()))
 +                    {
 +                        //the viewer cleans up the log directory on clean shutdown
 +                        //but is ignorant of the locking table.
 +                        if (!sendCrashLog((*lock)["dumpdir"].asString()))
 +                        {
 +                            newlocks.append(*lock);    //Failed to send log so don't delete it.
 +                        }
 +                        else
 +                        {
 +                            mKeyMaster.cleanupProcess((*lock)["dumpdir"].asString());
 +                        }
 +                    }
 +                }
 +            }
 +            else
 +            {
 +                LL_INFOS() << "Discarding corrupted entry from lock table." << LL_ENDL;
 +            }
 +        }
 +    }
 +
 +    if (rec)
 +    {
 +        newlocks.append(rec);
 +    }
 +
 +    mKeyMaster.putProcessList(newlocks);
 +    return true;
 +}
 +
 +void LLCrashLogger::updateApplication(const std::string& message)
 +{
 +    if (!message.empty()) LL_INFOS("CRASHREPORT") << message << LL_ENDL;
 +}
 +
 +bool LLCrashLogger::init()
 +{
 +    LL_DEBUGS("CRASHREPORT") << LL_ENDL;
 +
 +    LLCore::LLHttp::initialize();
 +
 +    // We assume that all the logs we're looking for reside on the current drive
 +    gDirUtilp->initAppDirs("SecondLife");
 +
 +    LLError::initForApplication(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""), gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
 +
 +    // Default to the product name "Second Life" (this is overridden by the -name argument)
 +    mProductName = "Second Life";
 +
 +    // Rename current log file to ".old"
 +    std::string old_log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "crashreport.log.old");
 +    std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "crashreport.log");
 +
 +#if LL_WINDOWS
 +    LLAPRFile::remove(old_log_file);
 +#endif
 +
 +    LLFile::rename(log_file.c_str(), old_log_file.c_str());
 +
 +    // Set the log file to crashreport.log
 +    LLError::logToFile(log_file);  //NOTE:  Until this line, LL_INFOS LL_WARNS, etc are blown to the ether.
 +
 +    LL_INFOS("CRASHREPORT") << "Crash reporter file rotation complete." << LL_ENDL;
 +
 +    // Handle locking
 +    bool locked = mKeyMaster.requestMaster();  //Request master locking file.  wait time is defaulted to 300S
 +
 +    while (!locked && mKeyMaster.isWaiting())
 +    {
 +        LL_INFOS("CRASHREPORT") << "Waiting for lock." << LL_ENDL;
 +#if LL_WINDOWS
 +        Sleep(1000);
 +#else
 +        ::sleep(1);
 +#endif
 +        locked = mKeyMaster.checkMaster();
 +    }
 +
 +    if (!locked)
 +    {
 +        LL_WARNS("CRASHREPORT") << "Unable to get master lock.  Another crash reporter may be hung." << LL_ENDL;
 +        return false;
 +    }
 +
 +    mCrashSettings.declareS32("CrashSubmitBehavior", CRASH_BEHAVIOR_ALWAYS_SEND,
 +                              "Controls behavior when viewer crashes "
 +                              "(0 = ask before sending crash report, "
 +                              "1 = always send crash report, "
 +                              "2 = never send crash report)");
 +
 +    init_curl();
 +    LLCore::HttpRequest::createService();
 +    LLCore::HttpRequest::startThread();
 +
 +    return true;
 +}
 +
 +// For cleanup code common to all platforms.
 +void LLCrashLogger::commonCleanup()
 +{
 +    term_curl();
 +    LLError::logToFile("");   //close crashreport.log
 +    SUBSYSTEM_CLEANUP(LLProxy);
 +}
 +
 +void LLCrashLogger::init_curl()
 +{
 +    curl_global_init(CURL_GLOBAL_ALL);
 +
 +    ssl_mutex_count = CRYPTO_num_locks();
 +    if (ssl_mutex_count > 0)
 +    {
 +        ssl_mutex_list = new LLCoreInt::HttpMutex *[ssl_mutex_count];
 +
 +        for (int i(0); i < ssl_mutex_count; ++i)
 +        {
 +            ssl_mutex_list[i] = new LLCoreInt::HttpMutex;
 +        }
 +
 +        CRYPTO_set_locking_callback(ssl_locking_callback);
 +        CRYPTO_THREADID_set_callback(ssl_thread_id_callback);
 +    }
 +}
 +
 +
 +void LLCrashLogger::term_curl()
 +{
 +    CRYPTO_set_locking_callback(NULL);
 +    for (int i(0); i < ssl_mutex_count; ++i)
 +    {
 +        delete ssl_mutex_list[i];
 +    }
 +    delete[] ssl_mutex_list;
 +}
 +
 +
 +void LLCrashLogger::ssl_thread_id_callback(CRYPTO_THREADID* pthreadid)
 +{
 +#if LL_WINDOWS
 +    CRYPTO_THREADID_set_pointer(pthreadid, GetCurrentThread());
 +#else
 +    CRYPTO_THREADID_set_pointer(pthreadid, reinterpret_cast<void*>(pthread_self()));
 +#endif
 +}
 +
 +
 +void LLCrashLogger::ssl_locking_callback(int mode, int type, const char * /* file */, int /* line */)
 +{
 +    if (type >= 0 && type < ssl_mutex_count)
 +    {
 +        if (mode & CRYPTO_LOCK)
 +        {
 +            ssl_mutex_list[type]->lock();
 +        }
 +        else
 +        {
 +            ssl_mutex_list[type]->unlock();
 +        }
 +    }
 +}
 +
 diff --git a/indra/llcrashlogger/llcrashlogger.h b/indra/llcrashlogger/llcrashlogger.h index ddab0d01eb..9952255810 100644 --- a/indra/llcrashlogger/llcrashlogger.h +++ b/indra/llcrashlogger/llcrashlogger.h @@ -1,97 +1,97 @@ -/**  -* @file llcrashlogger.h -* @brief Crash Logger Definition -* -* $LicenseInfo:firstyear=2003&license=viewerlgpl$ -* Second Life Viewer Source Code -* Copyright (C) 2010, Linden Research, Inc. -*  -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; -* version 2.1 of the License only. -*  -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU -* Lesser General Public License for more details. -*  -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA -*  -* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA -* $/LicenseInfo$ -*/ -#ifndef LLCRASHLOGGER_H -#define LLCRASHLOGGER_H - -#include <vector> - -#include "linden_common.h" - -#include "llapp.h" -#include "llsd.h" -#include "llcontrol.h" -#include "llcrashlock.h" -#include "_mutex.h" - -// We shouldn't have to know the exact declaration of CRYPTO_THREADID, but VS -// 2017 complains if we forward-declare it as simply 'struct CRYPTO_THREADID'. -struct crypto_threadid_st; -typedef crypto_threadid_st CRYPTO_THREADID; - -// Crash reporter behavior -const S32 CRASH_BEHAVIOR_ASK = 0; -const S32 CRASH_BEHAVIOR_ALWAYS_SEND = 1; -const S32 CRASH_BEHAVIOR_NEVER_SEND = 2; - -class LLCrashLogger : public LLApp -{ -public: -	LLCrashLogger(); -	virtual ~LLCrashLogger(); -	std::string loadCrashURLSetting(); -    bool readFromXML(LLSD& dest, const std::string& filename ); -	void gatherFiles(); -    void mergeLogs( LLSD src_sd ); - -	virtual void gatherPlatformSpecificFiles() {} -    bool sendCrashLog(std::string dump_dir); -	bool sendCrashLogs(); -	LLSD constructPostData(); -	virtual void updateApplication(const std::string& message = LLStringUtil::null); -	virtual bool init(); -	virtual bool frame() = 0; -	virtual bool cleanup() = 0; -	void commonCleanup(); -	void setUserText(const std::string& text) { mCrashInfo["UserNotes"] = text; } -	S32 getCrashBehavior() { return mCrashBehavior; } -	bool runCrashLogPost(std::string host, LLSD data, std::string msg, int retries, int timeout); -	bool readMinidump(std::string minidump_path); - -protected: -    static void init_curl(); -    static void term_curl(); -    static void ssl_thread_id_callback(CRYPTO_THREADID*); -    static void ssl_locking_callback(int mode, int type, const char * file, int line); - -	S32 mCrashBehavior; -	bool mCrashInPreviousExec; -	std::map<std::string, std::string> mFileMap; -	std::string mGridName; -	LLControlGroup mCrashSettings; -	std::string mProductName; -	LLSD mCrashInfo; -	std::string mCrashHost; -	std::string mAltCrashHost; -	LLSD mDebugLog; -	bool mSentCrashLogs; -    LLCrashLock mKeyMaster; - -    static int ssl_mutex_count; -    static LLCoreInt::HttpMutex ** ssl_mutex_list; - -}; - -#endif //LLCRASHLOGGER_H +/**
 +* @file llcrashlogger.h
 +* @brief Crash Logger Definition
 +*
 +* $LicenseInfo:firstyear=2003&license=viewerlgpl$
 +* Second Life Viewer Source Code
 +* Copyright (C) 2010, Linden Research, Inc.
 +*
 +* This library is free software; you can redistribute it and/or
 +* modify it under the terms of the GNU Lesser General Public
 +* License as published by the Free Software Foundation;
 +* version 2.1 of the License only.
 +*
 +* This library is distributed in the hope that it will be useful,
 +* but WITHOUT ANY WARRANTY; without even the implied warranty of
 +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 +* Lesser General Public License for more details.
 +*
 +* You should have received a copy of the GNU Lesser General Public
 +* License along with this library; if not, write to the Free Software
 +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 +*
 +* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 +* $/LicenseInfo$
 +*/
 +#ifndef LLCRASHLOGGER_H
 +#define LLCRASHLOGGER_H
 +
 +#include <vector>
 +
 +#include "linden_common.h"
 +
 +#include "llapp.h"
 +#include "llsd.h"
 +#include "llcontrol.h"
 +#include "llcrashlock.h"
 +#include "_mutex.h"
 +
 +// We shouldn't have to know the exact declaration of CRYPTO_THREADID, but VS
 +// 2017 complains if we forward-declare it as simply 'struct CRYPTO_THREADID'.
 +struct crypto_threadid_st;
 +typedef crypto_threadid_st CRYPTO_THREADID;
 +
 +// Crash reporter behavior
 +const S32 CRASH_BEHAVIOR_ASK = 0;
 +const S32 CRASH_BEHAVIOR_ALWAYS_SEND = 1;
 +const S32 CRASH_BEHAVIOR_NEVER_SEND = 2;
 +
 +class LLCrashLogger : public LLApp
 +{
 +public:
 +    LLCrashLogger();
 +    virtual ~LLCrashLogger();
 +    std::string loadCrashURLSetting();
 +    bool readFromXML(LLSD& dest, const std::string& filename );
 +    void gatherFiles();
 +    void mergeLogs( LLSD src_sd );
 +
 +    virtual void gatherPlatformSpecificFiles() {}
 +    bool sendCrashLog(std::string dump_dir);
 +    bool sendCrashLogs();
 +    LLSD constructPostData();
 +    virtual void updateApplication(const std::string& message = LLStringUtil::null);
 +    virtual bool init();
 +    virtual bool frame() = 0;
 +    virtual bool cleanup() = 0;
 +    void commonCleanup();
 +    void setUserText(const std::string& text) { mCrashInfo["UserNotes"] = text; }
 +    S32 getCrashBehavior() { return mCrashBehavior; }
 +    bool runCrashLogPost(std::string host, LLSD data, std::string msg, int retries, int timeout);
 +    bool readMinidump(std::string minidump_path);
 +
 +protected:
 +    static void init_curl();
 +    static void term_curl();
 +    static void ssl_thread_id_callback(CRYPTO_THREADID*);
 +    static void ssl_locking_callback(int mode, int type, const char * file, int line);
 +
 +    S32 mCrashBehavior;
 +    bool mCrashInPreviousExec;
 +    std::map<std::string, std::string> mFileMap;
 +    std::string mGridName;
 +    LLControlGroup mCrashSettings;
 +    std::string mProductName;
 +    LLSD mCrashInfo;
 +    std::string mCrashHost;
 +    std::string mAltCrashHost;
 +    LLSD mDebugLog;
 +    bool mSentCrashLogs;
 +    LLCrashLock mKeyMaster;
 +
 +    static int ssl_mutex_count;
 +    static LLCoreInt::HttpMutex ** ssl_mutex_list;
 +
 +};
 +
 +#endif //LLCRASHLOGGER_H
 | 
