Example #1
0
void FS_LoadBasePak()
{
	Cmd::Args extrapaks(fs_extrapaks.Get());
	for (const auto& x: extrapaks) {
		if (!FS_LoadPak(x.c_str()))
			Com_Error(errorParm_t::ERR_FATAL, "Could not load extra pak '%s'\n", x.c_str());
	}

	if (!FS_LoadPak(fs_basepak.Get().c_str())) {
		Log::Notice("Could not load base pak '%s', falling back to default\n", fs_basepak.Get().c_str());
		if (!FS_LoadPak(DEFAULT_BASE_PAK))
			Com_Error(errorParm_t::ERR_FATAL, "Could not load default base pak '%s'", DEFAULT_BASE_PAK);
	}
}
Example #2
0
/*
=================
SV_MasterGameStat
=================
*/
void SV_MasterGameStat( const char *data )
{
	netadr_t adr;

	if ( !isLanOnly.Get() )
	{
		return; // only dedicated servers send stats
	}

	Com_Printf( "Resolving %s\n", MASTER_SERVER_NAME );

	switch ( NET_StringToAdr( MASTER_SERVER_NAME, &adr, NA_UNSPEC ) )
	{
		case 0:
			Com_Printf( "Couldn't resolve master address: %s\n", MASTER_SERVER_NAME );
			return;

		case 2:
			adr.port = BigShort( PORT_MASTER );

		default:
			break;
	}

	Com_Printf( "%s resolved to %s\n", MASTER_SERVER_NAME,
	            NET_AdrToStringwPort( adr ) );

	Com_Printf( "Sending gamestat to %s\n", MASTER_SERVER_NAME );
	NET_OutOfBandPrint( NS_SERVER, adr, "gamestat %s", data );
}
Example #3
0
/*
=================
CM_WriteAreaBits

Writes a bit vector of all the areas
that are in the same flood as the area parameter
Returns the number of bytes needed to hold all the bits.

The bits are OR'd in, so you can CM_WriteAreaBits from multiple
viewpoints and get the union of all visible areas.

This is used to cull non-visible entities from snapshots
=================
*/
int CM_WriteAreaBits( byte *buffer, int area )
{
	int i;
	int floodnum;
	int bytes;

	bytes = ( cm.numAreas + 7 ) >> 3;

	if ( cm_noAreas.Get() || area == -1 )
	{
		// for debugging, send everything
		memset( buffer, 255, bytes );
	}
	else
	{
		floodnum = cm.areas[ area ].floodnum;

		for ( i = 0; i < cm.numAreas; i++ )
		{
			if ( cm.areas[ i ].floodnum == floodnum || area == -1 )
			{
				buffer[ i >> 3 ] |= 1 << ( i & 7 );
			}
		}
	}
Example #4
0
void BreakpadInit() {
    if (!enableBreakpad.Get()) {
        return;
    }

    if (BreakpadInitInternal()) {
        crashDumpLogs.Notice("Starting crash logging server");
    }
}
Example #5
0
bool FS_LoadServerPaks(const char* paks, bool isDemo)
{
	Cmd::Args args(paks);
	fs_missingPaks.clear();
	for (auto& x: args) {
		std::string name, version;
		Util::optional<uint32_t> checksum;
		if (!FS::ParsePakName(x.data(), x.data() + x.size(), name, version, checksum)) {
			Com_Error(errorParm_t::ERR_DROP, "Invalid pak reference from server: %s", x.c_str());
		} else if (!checksum) {
			if (isDemo || allowRemotePakDir.Get())
				continue;
			Com_Error(errorParm_t::ERR_DROP, "The server is configured to load game data from a directory which makes it incompatible with remote clients.");
		}

		// Keep track of all missing paks
		const FS::PakInfo* pak = FS::FindPak(name, version, *checksum);
		if (!pak)
			fs_missingPaks.emplace_back(std::move(name), std::move(version), *checksum);
		else {
			try {
				FS::PakPath::LoadPakExplicit(*pak, *checksum);
			} catch (std::system_error&) {
				fs_missingPaks.emplace_back(std::move(name), std::move(version), *checksum);
			}
		}
	}

	// Load extra paks as well for demos
	if (isDemo) {
		Cmd::Args extrapaks(fs_extrapaks.Get());
		for (auto& x: extrapaks) {
			if (!FS_LoadPak(x.c_str()))
				Com_Error(errorParm_t::ERR_FATAL, "Could not load extra pak '%s'\n", x.c_str());
		}
	}

	return fs_missingPaks.empty();
}
Example #6
0
void SV_MasterHeartbeat( const char *hbname )
{
	int             i;
	int             netenabled;

	netenabled = Cvar_VariableIntegerValue( "net_enabled" );

	if ( isLanOnly.Get() || !( netenabled & ( NET_ENABLEV4 | NET_ENABLEV6 ) ) )
	{
		return; // only dedicated servers send heartbeats
	}

	// if not time yet, don't send anything
	if ( svs.time < svs.nextHeartbeatTime )
	{
		return;
	}

	svs.nextHeartbeatTime = svs.time + HEARTBEAT_MSEC;

	SV_ResolveMasterServers();

	// send to group masters
	for ( i = 0; i < MAX_MASTER_SERVERS; i++ )
	{
		if ( masterServerAddr[ i ].ipv4.type == NA_BAD && masterServerAddr[ i ].ipv6.type == NA_BAD )
		{
			continue;
		}

		Com_Printf( "Sending heartbeat to %s\n", sv_master[ i ]->string );

		// this command should be changed if the server info / status format
		// ever incompatibly changes

		if ( masterServerAddr[ i ].ipv4.type != NA_BAD )
		{
			NET_OutOfBandPrint( NS_SERVER, masterServerAddr[ i ].ipv4, "heartbeat %s\n", hbname );
		}

		if ( masterServerAddr[ i ].ipv6.type != NA_BAD )
		{
			NET_OutOfBandPrint( NS_SERVER, masterServerAddr[ i ].ipv6, "heartbeat %s\n", hbname );
		}
	}
}
Example #7
0
/*
====================
CM_AreasConnected

====================
*/
bool CM_AreasConnected( int area1, int area2 )
{
	if ( cm_noAreas.Get() )
	{
		return true;
	}

	if ( area1 < 0 || area2 < 0 )
	{
		return false;
	}

	if ( area1 >= cm.numAreas || area2 >= cm.numAreas )
	{
		Sys::Drop( "area >= cm.numAreas" );
	}

	if ( cm.areas[ area1 ].floodnum == cm.areas[ area2 ].floodnum )
	{
		return true;
	}

	return false;
}
Example #8
0
namespace Sys {

static std::string CrashDumpPath() {
    return FS::Path::Build(FS::GetHomePath(), "crashdump/");
}

bool CreateCrashDumpPath() {
    crashDumpLogs.Debug("Creating crash dump path: %s", CrashDumpPath());
    std::error_code createDirError;
    FS::RawPath::CreatePathTo(FS::Path::Build(CrashDumpPath(), "x"), createDirError);
    bool success = createDirError == createDirError.default_error_condition();
    if (!success) {
#ifdef _WIN32
        crashDumpLogs.Warn("Failed to create crash dump directory: %s", Win32StrError(GetLastError()));
#else
        crashDumpLogs.Warn("Failed to create crash dump directory: %s", strerror(errno));
#endif
    }
    return success;
}

// Records a crash dump sent from the VM in minidump format. This is the same
// format that Breakpad uses, but nacl minidump does not require Breakpad to work.
void NaclCrashDump(const std::vector<uint8_t>& dump, Str::StringRef vmName) {
    const size_t maxDumpSize = (512 + 64) * 1024; // from http://src.chromium.org/viewvc/native_client/trunk/src/native_client/src/untrusted/minidump_generator/minidump_generator.cc
    if(dump.size() > maxDumpSize) { // sanity check: shouldn't be bigger than the buffer in nacl
        crashDumpLogs.Warn("Ignoring NaCl crash dump request: size too large");
    } else {
        auto time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock().now().time_since_epoch()).count();
        std::string path = FS::Path::Build(CrashDumpPath(), Str::Format("crash-nacl-%s-%s.dmp", vmName, std::to_string(time)));

        // Note: the file functions always use binary mode on Windows so there shouldn't be any lossiness.
        try {
            auto file = FS::RawPath::OpenWrite(path);
            file.Write(dump.data(), dump.size());
            file.Close();
            crashDumpLogs.Notice("Wrote crash dump to %s", path);
        } catch (const std::system_error& error) {
            crashDumpLogs.Warn("Error while writing crash dump: %s", error.what());
        }
    }
}

#ifdef USE_BREAKPAD

static std::string CrashServerPath() {
#ifdef _WIN32
    std::string name = "crash_server.exe";
#else
    std::string name = "crash_server";
#endif
    return FS::Path::Build(FS::GetLibPath(), name);
}

static Cvar::Cvar<bool> enableBreakpad("common.breakpad.enabled", "If enabled on startup, starts a process for recording crash dumps", Cvar::TEMPORARY, true);

#ifdef _WIN32

static std::unique_ptr<google_breakpad::ExceptionHandler> crashHandler;

static bool BreakpadInitInternal() {
    std::string crashDir = CrashDumpPath();
    std::string executable = CrashServerPath();
    std::string pipeName = GetSingletonSocketPath() + "-crash";
    DWORD pid = GetCurrentProcessId();
    std::string cmdLine = "\"" + executable + "\" " + pipeName + " \"" + crashDir + " \" " + std::to_string(pid);
    crashDumpLogs.Debug("Starting crash server with the following command line: %s", cmdLine);

    STARTUPINFOA startInfo{};
    startInfo.cb = sizeof(startInfo);
    startInfo.dwFlags = 0;

    PROCESS_INFORMATION procInfo;
    if (!CreateProcessA(&executable[0], &cmdLine[0],
        NULL, NULL, FALSE, 0, NULL, NULL,
        &startInfo, &procInfo))
    {
        crashDumpLogs.Warn("Failed to start crash logging server: %s", Win32StrError(GetLastError()));
        return false;
    }

    CloseHandle(procInfo.hProcess);
    CloseHandle(procInfo.hThread);

    std::wstring wPipeName = Str::UTF8To16(pipeName);
    crashHandler.reset(new google_breakpad::ExceptionHandler(
        Str::UTF8To16(crashDir),
        nullptr,
        nullptr,
        nullptr,
        google_breakpad::ExceptionHandler::HANDLER_ALL,
        MiniDumpNormal,
        wPipeName.c_str(),
        nullptr));
    return true;
}

#elif defined(__linux__)

std::unique_ptr<google_breakpad::ExceptionHandler> crashHandler;

static bool CreateReportChannel(int& fdServer, int& fdClient) {
    if (!google_breakpad::CrashGenerationServer::CreateReportChannel(&fdServer, &fdClient)) {
        return false;
    }
    // Breakpad's function makes the client fd inheritable and the server not,
    // but we want the opposite.
    int oldflags;
    return -1 != (oldflags = fcntl(fdServer, F_GETFD))
        && -1 != fcntl(fdServer, F_SETFD, oldflags & ~FD_CLOEXEC)
        && -1 != (oldflags = fcntl(fdClient, F_GETFD))
        && -1 != fcntl(fdClient, F_SETFD, oldflags | FD_CLOEXEC);
}

static bool BreakpadInitInternal() {
    int fdServer, fdClient;
    if (!CreateReportChannel(fdServer, fdClient)) {
        crashDumpLogs.Warn("Failed to start crash logging server");
        return false;
    }
	// allocate exec arguments before forking to avoid malloc use
	std::string fdServerStr = std::to_string(fdServer);
	std::string crashDir = CrashDumpPath();
	std::string exePath = CrashServerPath();

    crashDumpLogs.Debug("Starting crash server with the following command line: %s %s %s <child pid>",
                        exePath.c_str(),
                        fdServerStr.c_str(),
                        crashDir.c_str());

    pid_t pid = fork();
    if (pid == -1) {
        crashDumpLogs.Warn("Failed to start crash logging server: %s", strerror(errno));
        return false;
    } else if (pid != 0) { // Breakpad server MUST be in parent of engine process
		char pidStr[16]; 
		snprintf(pidStr, sizeof(pidStr), "%d", pid);
        const char* args[] = { exePath.c_str(), fdServerStr.c_str(), crashDir.c_str(), pidStr, nullptr };
        execv(exePath.c_str(), const_cast<char * const *>(args));
        _exit(1);
    }

    crashHandler.reset(new google_breakpad::ExceptionHandler(
        google_breakpad::MinidumpDescriptor{}, nullptr, nullptr,
        nullptr, true, fdClient));
    return true;
}

#endif // linux

void BreakpadInit() {
    if (!enableBreakpad.Get()) {
        return;
    }

    if (BreakpadInitInternal()) {
        crashDumpLogs.Notice("Starting crash logging server");
    }
}

#else // USE_BREAKPAD

void BreakpadInit() {
}

#endif // USE_BREAKPAD

} // namespace Sys