/* * ============================================================================= * Accelerator Extension * Copyright (C) 2011 Asher Baker (asherkin). All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License, version 3.0, as published by the * Free Software Foundation. * * This program 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ #include "extension.h" #include #include "MemoryDownloader.h" #include "client/linux/handler/exception_handler.h" #include #include #include Accelerator g_accelerator; SMEXT_LINK(&g_accelerator); IWebternet *webternet; static IThreadHandle *uploadThread; ConVar acceleratorVersion("accelerator_version", SMEXT_CONF_VERSION, FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY, SMEXT_CONF_DESCRIPTION " Version"); char buffer[255]; google_breakpad::ExceptionHandler *handler = NULL; void (*SignalHandler)(int, siginfo_t *, void *); const int kExceptionSignals[] = { SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS }; const int kNumHandledSignals = sizeof(kExceptionSignals) / sizeof(kExceptionSignals[0]); static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded) { printf("Wrote minidump to: %s\n", descriptor.path()); return succeeded; } void OnGameFrame(bool simulating) { bool weHaveBeenFuckedOver = false; struct sigaction oact; for (int i = 0; i < kNumHandledSignals; ++i) { sigaction(kExceptionSignals[i], NULL, &oact); if (oact.sa_sigaction != SignalHandler) { weHaveBeenFuckedOver = true; break; } } if (!weHaveBeenFuckedOver) { return; } struct sigaction act; memset(&act, 0, sizeof(act)); sigemptyset(&act.sa_mask); for (int i = 0; i < kNumHandledSignals; ++i) { sigaddset(&act.sa_mask, kExceptionSignals[i]); } act.sa_sigaction = SignalHandler; act.sa_flags = SA_ONSTACK | SA_SIGINFO; for (int i = 0; i < kNumHandledSignals; ++i) { sigaction(kExceptionSignals[i], &act, NULL); } } void UploadCrashDump(const char *path) { IWebForm *form = webternet->CreateForm(); form->AddString("UserID", g_pSM->GetCoreConfigValue("MinidumpAccount")); form->AddFile("upload_file_minidump", path); MemoryDownloader data; IWebTransfer *xfer = webternet->CreateSession(); xfer->SetFailOnHTTPError(true); if (!xfer->PostAndDownload("http://crash.limetech.org/submit", form, &data, NULL)) { META_CONPRINTF(">>> UPLOAD FAILED\n"); } else { META_CONPRINTF(">>> UPLOADED CRASH DUMP"); META_CONPRINTF("%s", data.GetBuffer()); } } void Accelerator::OnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax) { DIR *dumps = opendir(buffer); dirent *dump; char path[512]; while ((dump = readdir(dumps)) != NULL) { if (dump->d_type == DT_DIR) continue; META_CONPRINTF(">>> UPLOADING %s\n", dump->d_name); g_pSM->Format(path, sizeof(path), "%s/%s", buffer, dump->d_name); UploadCrashDump(path); unlink(path); } closedir(dumps); } bool Accelerator::SDK_OnLoad(char *error, size_t maxlength, bool late) { sharesys->AddDependency(myself, "webternet.ext", true, true); SM_GET_IFACE(WEBTERNET, webternet); g_pSM->BuildPath(Path_SM, buffer, 255, "data/dumps"); google_breakpad::MinidumpDescriptor descriptor(buffer); handler = new google_breakpad::ExceptionHandler(descriptor, NULL, dumpCallback, NULL, true, -1); struct sigaction oact; sigaction(SIGSEGV, NULL, &oact); SignalHandler = oact.sa_sigaction; g_pSM->AddGameFrameHook(OnGameFrame); return true; } bool Accelerator::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late) { GET_V_IFACE_CURRENT(GetEngineFactory, g_pCVar, ICvar, CVAR_INTERFACE_VERSION); ConVar_Register(0, this); return true; } void Accelerator::SDK_OnUnload() { g_pSM->RemoveGameFrameHook(OnGameFrame); } bool Accelerator::SDK_OnMetamodUnload(char *error, size_t maxlen) { return true; } bool Accelerator::RegisterConCommandBase(ConCommandBase *pCommand) { META_REGCVAR(pCommand); return true; }