/
BirdLeon
/
ROBLOX2016
Обзор
Документация
Войти
/
BirdLeon
/
ROBLOX2016
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
RCCService/RCCService.cpp
785 строк
19 KB
PatoFlamejanteTV
full source code
19 дек 2024, 19:11
19 дек 2024, 19:11
05db15d
Код
Авторство
О чём код?
// RCCService.cpp : Defines the entry point for the console application. // #include "stdafx.h" #define _CRTDBG_MAP_ALLOC #include <stdlib.h> #include <crtdbg.h> #include "conio.h" #include "gSOAP/generated/RCCServiceSoap.nsmap" #include "gSOAP/generated/soapRCCServiceSoapService.h" #include "logmanager.h" #include "rbx/boost.hpp" #include "Util/WinHeap.h" #include "Util/StandardOut.h" #include "rbx/TaskScheduler.h" #include "Util/Statistics.h" #include "util/Http.h" #include "v8datamodel/datamodel.h" #include "OperationalSecurity.h" #pragma optimize( "", off ) static long requestCount = 0; extern long diagCount; extern long batchJobCount; extern long openJobCount; extern long closeJobCount; extern long helloWorldCount; extern long getVersionCount; extern long renewLeaseCount; extern long executeCount; extern long getExpirationCount; extern long getStatusCount; extern long getAllJobsCount; extern long closeExpiredJobsCount; extern long closeAllJobsCount; #ifdef RBX_TEST_BUILD extern std::string RCCServiceSettingsKeyOverwrite; #endif void process_request(RCCServiceSoapService *service) { ::InterlockedIncrement(&requestCount); try { service->serve(); delete service; } catch (...) { RBXCRASH(); } ::InterlockedDecrement(&requestCount); } static void StringCrash(const char* s) { char str[256]; strncpy_s(str, 256, s, 256); RBXCRASH(); } template <class Soap> class ExceptionAwareSoap : public Soap { public: virtual int dispatch() { try { //printf("%s\n", action); return Soap::dispatch(); } catch (std::exception& e) { return soap_receiver_fault(this, e.what(), NULL); // return fault to sender } catch (std::string& s) { StringCrash(s.c_str()); return soap_receiver_fault(this, s.c_str(), NULL); // return fault to sender } catch (...) { RBXCRASH(); return soap_receiver_fault(this, "Unexpected C++ exception type", NULL); // return fault to sender } } virtual RCCServiceSoapService *copy() { ExceptionAwareSoap<Soap> *dup = new ExceptionAwareSoap<Soap>(); soap_copy_context(dup, this); return dup; } }; ExceptionAwareSoap<RCCServiceSoapService> service; #define SVCNAME TEXT("RCCService") // http://msdn2.microsoft.com/en-us/library/ms687416(VS.85).aspx // // Purpose: // Logs messages to the event log // // Parameters: // szFunction - name of function that failed // // Return value: // None // // Remarks: // The service must have an entry in the Application event log. // VOID SvcReportEvent(WORD type, LPCTSTR szFunction) { HANDLE hEventSource = ::RegisterEventSource(NULL, SVCNAME); if( NULL != hEventSource ) { LPCTSTR* lpStrings = &szFunction; ReportEvent(hEventSource, // event log source handle type, // event type to log 0, // event category 0x20000001L, // event identifier (GENERIC_MESSAGE) which comes from Message.mc 0, // user security identifier (optional) 1, // number of strings to merge with message 0, // size of binary data, in bytes lpStrings, // array of strings to merge with message NULL); // address of binary data DeregisterEventSource(hEventSource); } } void start_CWebService(LPCTSTR contentpath, bool crashUploaderOnly); static void startupRCC(int port, LPCTSTR contentpath, bool crashUploaderOnly) { printf("Service starting...\n"); start_CWebService(contentpath, crashUploaderOnly); //service.send_timeout = 60; // 60 seconds //service.recv_timeout = 60; // 60 seconds service.accept_timeout = 1; // server stops after 1 second //soap.max_keep_alive = 100; // max keep-alive sequence SOAP_SOCKET m = service.bind(NULL, port, 100); if (!soap_valid_socket(m)) throw std::runtime_error(*soap_faultstring(&service)); char buffer[64]; sprintf_s(buffer, 64, "Service Started on port %d", port); RBX::StandardOut::singleton()->print(RBX::MESSAGE_SENSITIVE, buffer); SvcReportEvent(EVENTLOG_INFORMATION_TYPE, buffer); } DWORD CALLBACK process_request_func(LPVOID param) { process_request((RCCServiceSoapService*) param); return 0; } static void stepRCC() { if (requestCount>100) throw std::runtime_error(RBX::format("%d outstanding requests, execute=%d, openJob=%d, batchJob=%d, diag=%d, getVersion=%d, renewLease=%d, getAllJobs=%d, getStatusCount=%d, closeExpiredJobs=%d, closeJob=%d, helloWorld=%d, getExpiration=%d, closeAllJobs=%d", requestCount, executeCount, openJobCount, batchJobCount, diagCount, getVersionCount, renewLeaseCount, getAllJobsCount, getStatusCount, closeExpiredJobsCount, closeJobCount, helloWorldCount, getExpirationCount, closeAllJobsCount)); SOAP_SOCKET s = service.accept(); if (!soap_valid_socket(s)) { if (service.errnum) throw std::runtime_error(*soap_faultstring(&service)); return; } RCCServiceSoapService* copy = service.copy(); // make a safe copy if (!copy) throw std::runtime_error(*soap_faultstring(&service)); if (!QueueUserWorkItem(&process_request_func, copy, WT_EXECUTELONGFUNCTION)) RBXCRASH(); } void stop_CWebService(); static void shutdownRCC() { printf("Service shutting down...\n"); stop_CWebService(); } SERVICE_STATUS_HANDLE handle = 0; SERVICE_STATUS status = { SERVICE_WIN32_OWN_PROCESS, SERVICE_STOPPED, SERVICE_ACCEPT_STOP }; HANDLE stopped; // manual, not signaled void UpdateState(DWORD state) { status.dwCurrentState = state; ::SetServiceStatus(handle, &status); } static int parsePort(int argc, _TCHAR* argv[]) { int port = 64989; for (int i = 1; i<argc; ++i) { if (argv[i][0] == _T('/') || argv[i][0] == _T('-')) continue; port = atoi(argv[i]); } return port; } static bool parseBreakRequest(int argc, _TCHAR* argv[]) { for (int i = 1; i<argc; ++i) { if (argv[i][0] == _T('/')) argv[i][0] = _T('-'); if (_tcsicmp(argv[i], _T("-Break")) == 0) { return true; } } return false; } static LPCTSTR parseContent(int argc, _TCHAR* argv[]) { const _TCHAR szTag[] = _T("-Content:"); int cchTagLen = (sizeof(szTag)/sizeof(_TCHAR)); static const _TCHAR szDefaultValue[] = _T("Content\\"); for (int i = 1; i<argc; ++i) { if (argv[i][0] == _T('/')) argv[i][0] = _T('-'); if (_tcsncicmp(argv[i], szTag, cchTagLen-1) == 0) { // return the part after the tag. return argv[i] + cchTagLen-1; } } return szDefaultValue; } static LPCTSTR parse(const _TCHAR szTag[], int tagLen, int argc, _TCHAR* argv[]) { static const _TCHAR szDefaultValue[] = _T(""); for (int i = 1; i<argc; ++i) { if (argv[i][0] == _T('/')) argv[i][0] = _T('-'); if (_tcsncicmp(argv[i], szTag, tagLen-1) == 0) { // return the part after the tag. return argv[i] + tagLen-1; } } return szDefaultValue; } static int parsePlaceId(int argc, _TCHAR* argv[]) { const _TCHAR szTag[] = _T("-PlaceId:"); LPCTSTR placeId = parse(szTag, sizeof(szTag), argc, argv); if (placeId == "") return -1; return atoi(placeId); } #ifdef RBX_TEST_BUILD static LPCTSTR parseMD5(int argc, _TCHAR* argv[]) { const _TCHAR szTag[] = _T("-Md5:"); return parse(szTag, sizeof(szTag), argc, argv); } static LPCTSTR parseSettingsKey(int argc, _TCHAR* argv[]) { const _TCHAR szTag[] = _T("-SettingsKey:"); return parse(szTag, sizeof(szTag), argc, argv); } #endif void WINAPI Handler(DWORD control) { //ASSERT(SERVICE_CONTROL_STOP == control); UpdateState(SERVICE_STOP_PENDING); RBX::StandardOut::singleton()->print(RBX::MESSAGE_INFO, "SERVICE_STOP_PENDING"); SvcReportEvent(EVENTLOG_INFORMATION_TYPE, "SERVICE_STOP_PENDING"); // Perform shutdown steps here. shutdownRCC(); ::WaitForSingleObject(stopped, INFINITE); UpdateState(SERVICE_STOPPED); RBX::StandardOut::singleton()->print(RBX::MESSAGE_INFO, "SERVICE_STOPPED"); SvcReportEvent(EVENTLOG_INFORMATION_TYPE, "SERVICE_STOPPED"); } VOID WINAPI ServiceMain( DWORD dwArgc, LPTSTR *lpszArgv ) { stopped = CreateEvent( NULL, // default security attributes TRUE, // manual-reset event FALSE, // initial state is not signaled TEXT("Stopped") // object name ); handle = ::RegisterServiceCtrlHandler(SVCNAME, Handler); //ASSERT(0 != handle); UpdateState(SERVICE_START_PENDING); // Perform any startup steps here. try { int port = parsePort(dwArgc, lpszArgv); LPCTSTR contentDir = parseContent(dwArgc, lpszArgv); startupRCC(port, contentDir, false); UpdateState(SERVICE_RUNNING); } catch (std::exception& e) { RBX::StandardOut::singleton()->print(RBX::MESSAGE_ERROR, e); SvcReportEvent(EVENTLOG_ERROR_TYPE, e.what()); } bool breakRequest = parseBreakRequest(dwArgc, lpszArgv); while (SERVICE_RUNNING == status.dwCurrentState) { if (breakRequest) { ::DebugBreak(); breakRequest = false; } // Perform main service function here. try { stepRCC(); } catch (std::exception& e) { RBX::StandardOut::singleton()->print(RBX::MESSAGE_ERROR, e); SvcReportEvent(EVENTLOG_ERROR_TYPE, e.what()); } } ::SetEvent(stopped); } class CServiceHandle { SC_HANDLE handle; public: CServiceHandle(SC_HANDLE handle):handle(handle) {} ~CServiceHandle() { CloseServiceHandle(handle); } operator SC_HANDLE() const { return handle; } }; bool SvcUninstall(const char* name) { // Get a handle to the SCM database. CServiceHandle schSCManager = OpenSCManager( NULL, // local computer NULL, // ServicesActive database SC_MANAGER_ALL_ACCESS); // full access rights CServiceHandle schService = ::OpenService(schSCManager, name, DELETE); if (schService == NULL) { printf("OpenService failed (%d)\n", GetLastError()); return false; } bool result = DeleteService(schService) ? true : false; return result; } void SvcStart(const char* name) { // Get a handle to the SCM database. CServiceHandle schSCManager = OpenSCManager( NULL, // local computer NULL, // ServicesActive database SC_MANAGER_ALL_ACCESS); // full access rights CServiceHandle schService = ::OpenService(schSCManager, name, SERVICE_START); if (schService == NULL) { printf("OpenService failed (%d)\n", GetLastError()); return; } if (!StartService(schService, NULL, NULL)) printf("StartService failed (%d)\n", GetLastError()); else printf("Service Starting\n"); } void SvcStop(const char* name) { // Get a handle to the SCM database. CServiceHandle schSCManager = OpenSCManager( NULL, // local computer NULL, // ServicesActive database SC_MANAGER_ALL_ACCESS); // full access rights CServiceHandle schService = ::OpenService(schSCManager, name, SERVICE_STOP); if (schService == NULL) { printf("OpenService failed (%d)\n", GetLastError()); return; } SERVICE_STATUS serviceStatus; if (!ControlService(schService, SERVICE_CONTROL_STOP, &serviceStatus)) { printf("ControlService failed (%d)\n", GetLastError()); } } void EventLongUninstall() { CRegKey key; if (key.Open(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Eventlog\\Application", KEY_WRITE) == ERROR_SUCCESS) key.DeleteSubKey("RCCService"); } void EventLogInstall() { CRegKey key; if (key.Create(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Eventlog\\Application\\RCCService") != ERROR_SUCCESS) throw std::runtime_error("couldn't create RCCService reg key"); TCHAR szPath[MAX_PATH]; if( !GetModuleFileName( NULL, szPath, MAX_PATH ) ) throw std::runtime_error("GetModuleFileName failed"); key.SetStringValue("EventMessageFile", szPath, REG_EXPAND_SZ); key.SetDWORDValue("TypesSupported", 0x1f); } void SvcInstall() { TCHAR szPath[MAX_PATH]; if( !GetModuleFileName( NULL, szPath, MAX_PATH ) ) throw std::runtime_error("GetModuleFileName failed"); // Get a handle to the SCM database. CServiceHandle schSCManager = OpenSCManager( NULL, // local computer NULL, // ServicesActive database SC_MANAGER_CREATE_SERVICE); if (NULL == schSCManager) throw std::runtime_error("OpenSCManager failed"); // Create the service CServiceHandle schService = CreateService( schSCManager, // SCM database SVCNAME, // name of service "Roblox Compute Cloud Service", // service name to display SERVICE_ALL_ACCESS, // desired access SERVICE_WIN32_OWN_PROCESS, // service type SERVICE_AUTO_START, // start type SERVICE_ERROR_NORMAL, // error control type szPath, // path to service's binary NULL, // no load ordering group NULL, // no tag identifier NULL, // no dependencies NULL, // LocalSystem account NULL); // no password if (schService == NULL) { if (GetLastError()==ERROR_SERVICE_EXISTS) { printf("Service already installed\n"); return; } throw std::runtime_error("CreateService failed"); } else printf("Service installed successfully\n"); SERVICE_FAILURE_ACTIONS fa; fa.dwResetPeriod = 100; fa.lpRebootMsg = NULL; fa.lpCommand = NULL; fa.cActions = 3; SC_ACTION sa[3]; sa[0].Delay = 5000; sa[0].Type = SC_ACTION_RESTART; sa[1].Delay = 55000; sa[1].Type = SC_ACTION_RESTART; sa[2].Delay = 60000; sa[2].Type = SC_ACTION_RESTART; fa.lpsaActions = sa; if (!ChangeServiceConfig2(schService, SERVICE_CONFIG_FAILURE_ACTIONS, &fa)) throw std::runtime_error("ChangeServiceConfig2 failed"); } class Console { public: static bool done; Console() { SetConsoleCtrlHandler( (PHANDLER_ROUTINE) CtrlHandler, TRUE ); } static BOOL CtrlHandler( DWORD fdwCtrlType ) { switch( fdwCtrlType ) { case CTRL_SHUTDOWN_EVENT: case CTRL_BREAK_EVENT: case CTRL_C_EVENT: case CTRL_CLOSE_EVENT: done = true; return TRUE; default: return FALSE; } } }; bool Console::done = false; namespace RBX { extern bool nameThreads; } static boost::mutex keyLockMutex; void ReadAccessKey() { if (RBX::Http::accessKey.empty()) { boost::mutex::scoped_lock lock(keyLockMutex); if (RBX::Http::accessKey.empty()) { CRegKey key; if (SUCCEEDED(key.Open(HKEY_LOCAL_MACHINE, "Software\\ROBLOX Corporation\\Roblox\\", KEY_READ))) { CHAR keyData[MAX_PATH]; ULONG bufLen = MAX_PATH-1; if (SUCCEEDED(key.QueryStringValue("AccessKey", keyData, &bufLen))) { keyData[bufLen] = 0; RBX::Http::accessKey = std::string(keyData); RBX::StandardOut::singleton()->printf(RBX::MESSAGE_SENSITIVE, "Access key read: %s", RBX::Http::accessKey.c_str()); } } } } RBX::StandardOut::singleton()->printf(RBX::MESSAGE_SENSITIVE, "Current Access key: %s", RBX::Http::accessKey.c_str()); } class PrintfLogger { rbx::signals::scoped_connection messageConnection; HANDLE handle; rbx::spin_mutex mutex; public: PrintfLogger() :handle(GetStdHandle(STD_OUTPUT_HANDLE)) { messageConnection = RBX::StandardOut::singleton()->messageOut.connect(boost::bind(&PrintfLogger::onMessage, this, _1)); } protected: void onMessage(const RBX::StandardOutMessage& message) { rbx::spin_mutex::scoped_lock lock(mutex); switch (message.type) { case RBX::MESSAGE_OUTPUT: SetConsoleTextAttribute(handle, FOREGROUND_BLUE | FOREGROUND_INTENSITY); break; case RBX::MESSAGE_INFO: SetConsoleTextAttribute(handle, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); break; case RBX::MESSAGE_WARNING: SetConsoleTextAttribute(handle, FOREGROUND_RED | FOREGROUND_GREEN); break; case RBX::MESSAGE_ERROR: SetConsoleTextAttribute(handle, FOREGROUND_RED | FOREGROUND_INTENSITY); break; } printf("%s\n", message.message.c_str()); SetConsoleTextAttribute(handle, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); } }; int _tmain(int argc, _TCHAR* argv[]) { _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); static boost::scoped_ptr<PrintfLogger> standardOutLog(new PrintfLogger()); ReadAccessKey(); RBX::UTIL::setWindowsNoFragHeap(); try { bool isServiceCall = true; bool isConsole = false; bool isCrashUploader = false; for (int i = 1; i<argc; ++i) { if (argv[i][0] == _T('/')) argv[i][0] = _T('-'); if (_tcsicmp(argv[i], _T("-Install")) == 0) { EventLogInstall(); SvcInstall(); isServiceCall = false; continue; } if (_tcsicmp(argv[i], _T("-AQTime")) == 0) { RBX::nameThreads = false; continue; } if (_tcsicmp(argv[i], _T("-Uninstall")) == 0) { SvcUninstall(SVCNAME); EventLongUninstall(); isServiceCall = false; continue; } if (_tcsicmp(argv[i], _T("-Start")) == 0) { SvcStart(SVCNAME); isServiceCall = false; continue; } if (_tcsicmp(argv[i], _T("-Stop")) == 0) { SvcStop(SVCNAME); isServiceCall = false; continue; } if (_tcsicmp(argv[i], _T("-Console")) == 0) { isConsole = true; isServiceCall = false; continue; } if (_tcsicmp(argv[i], _T("-CrashReporter")) == 0) { isConsole = true; isServiceCall = false; isCrashUploader = true; continue; } } if (isConsole) { #ifdef RBX_TEST_BUILD RBX::DataModel::hash = parseMD5(argc, argv); RCCServiceSettingsKeyOverwrite = parseSettingsKey(argc, argv); #endif startupRCC(parsePort(argc, argv), parseContent(argc, argv), isCrashUploader); int placeId = parsePlaceId(argc, argv); if (placeId > -1) { std::stringstream buffer; std::ifstream gameServerFile("gameserver.txt", std::ios::in); if (gameServerFile.is_open()) { buffer << gameServerFile.rdbuf(); gameServerFile.close(); } buffer << "start(" << placeId << ", " << 53640 << ", '" << GetBaseURL() << "')"; std::string script = buffer.str(); RCCServiceSoapService* copy = service.copy(); // make a safe copy if (!copy) throw std::runtime_error(*soap_faultstring(&service)); ns1__Job job; job.id = "Test"; job.expirationInSeconds = 600; ns1__ScriptExecution se; se.name = &std::string("Start Server"); se.script = &script; _ns1__OpenJob openJob; _ns1__OpenJobResponse response; openJob.script = &se; openJob.job = &job; copy->OpenJob(&openJob, &response); } if(!isCrashUploader){ Console console; while (!console.done) { if (_kbhit()) if (_getch() == 27) break; else RBX::TaskScheduler::singleton().printDiagnostics(true); stepRCC(); } } shutdownRCC(); } else if (isServiceCall) { // This is an honest attempt to start the service. We're ready to begin!!! SERVICE_TABLE_ENTRY serviceTable[] = { { SVCNAME, ServiceMain }, { 0, 0 } }; if (!::StartServiceCtrlDispatcher(serviceTable)) { printf("StartServiceCtrlDispatcher failed (%d)\n", GetLastError()); } } } catch (std::exception& e) { RBX::StandardOut::singleton()->print(RBX::MESSAGE_ERROR, e); SvcReportEvent(EVENTLOG_ERROR_TYPE, e.what()); } RBX::clearLuaReadOnly(); } #pragma optimize( "", on )