/* * ============================================================================= * 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 <http://www.gnu.org/licenses/>. */ #include "extension.h" #include <IWebternet.h> #include "MemoryDownloader.h" #include "client/linux/handler/exception_handler.h" #include <signal.h> #include <dirent.h> #include <unistd.h> Accelerator g_accelerator; SMEXT_LINK(&g_accelerator); IWebternet *webternet; static IThreadHandle *uploadThread; 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)) { printf(">>> UPLOAD FAILED\n"); } else { printf(">>> UPLOADED CRASH DUMP"); printf("%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; printf(">>> 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"); if (!libsys->IsPathDirectory(buffer)) { if (!libsys->CreateFolder(buffer)) { if (error) g_pSM->Format(error, maxlength, "%s didn't exist and we couldn't create it :(", buffer); return false; } } 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; } void Accelerator::SDK_OnUnload() { g_pSM->RemoveGameFrameHook(OnGameFrame); }