mirror of https://github.com/BOINC/boinc.git
496 lines
17 KiB
C++
496 lines
17 KiB
C++
// Berkeley Open Infrastructure for Network Computing
|
|
// http://boinc.berkeley.edu
|
|
// Copyright (C) 2005 University of California
|
|
//
|
|
// This 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;
|
|
// either version 2.1 of the License, or (at your option) any later version.
|
|
//
|
|
// This software 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.
|
|
//
|
|
// To view the GNU Lesser General Public License visit
|
|
// http://www.gnu.org/copyleft/lesser.html
|
|
// or write to the Free Software Foundation, Inc.,
|
|
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
#if defined(__GNUG__) && !defined(__APPLE__)
|
|
#pragma implementation "BOINCClientManager.h"
|
|
#endif
|
|
|
|
#include "stdwx.h"
|
|
#include "diagnostics.h"
|
|
#include "LogBOINC.h"
|
|
#include "BOINCGUIApp.h"
|
|
#include "MainDocument.h"
|
|
#include "BOINCBaseFrame.h"
|
|
#include "AdvancedFrame.h"
|
|
#include "BOINCClientManager.h"
|
|
|
|
#ifdef __WXMAC__
|
|
#include "filesys.h"
|
|
#include "util.h"
|
|
|
|
enum {
|
|
NewStyleDaemon = 1,
|
|
OldStyleDaemon
|
|
};
|
|
#endif
|
|
|
|
#ifdef __WXMSW__
|
|
EXTERN_C BOOL IsBOINCServiceInstalled();
|
|
EXTERN_C BOOL IsBOINCServiceStarting();
|
|
EXTERN_C BOOL IsBOINCServiceRunning();
|
|
EXTERN_C BOOL IsBOINCServiceStopping();
|
|
EXTERN_C BOOL IsBOINCServiceStopped();
|
|
EXTERN_C BOOL StartBOINCService();
|
|
EXTERN_C BOOL StopBOINCService();
|
|
#endif
|
|
|
|
CBOINCClientManager::CBOINCClientManager() {
|
|
wxLogTrace(wxT("Function Start/End"), wxT("CBOINCClientManager::CBOINCClientManager - Function Begin"));
|
|
|
|
m_bBOINCStartedByManager = false;
|
|
m_lBOINCCoreProcessId = 0;
|
|
|
|
#ifdef __WXMSW__
|
|
m_hBOINCCoreProcess = NULL;
|
|
#endif
|
|
|
|
wxLogTrace(wxT("Function Start/End"), wxT("CBOINCClientManager::CBOINCClientManager - Function End"));
|
|
}
|
|
|
|
|
|
CBOINCClientManager::~CBOINCClientManager() {
|
|
wxLogTrace(wxT("Function Start/End"), wxT("CBOINCClientManager::~CBOINCClientManager - Function Begin"));
|
|
|
|
wxLogTrace(wxT("Function Start/End"), wxT("CBOINCClientManager::~CBOINCClientManager - Function End"));
|
|
}
|
|
|
|
|
|
bool CBOINCClientManager::AutoRestart() {
|
|
if (IsBOINCCoreRunning()) return true;
|
|
#ifndef __WXMAC__ // Mac can restart Client as a daemon
|
|
if (! m_bBOINCStartedByManager) return false;
|
|
#endif
|
|
m_lBOINCCoreProcessId = 0;
|
|
StartupBOINCCore();
|
|
return true;
|
|
}
|
|
|
|
|
|
bool CBOINCClientManager::IsSystemBooting() {
|
|
bool bReturnValue = false;
|
|
#if defined(__WXMSW__)
|
|
if (GetTickCount() < (1000*60*5)) bReturnValue = true; // If system has been up for less than 5 minutes
|
|
#elif defined(__WXMAC__)
|
|
if (TickCount() < (120*60)) bReturnValue = true; // If system has been up for less than 2 minutes
|
|
#endif
|
|
return bReturnValue;
|
|
}
|
|
|
|
|
|
int CBOINCClientManager::IsBOINCConfiguredAsDaemon() {
|
|
bool bReturnValue = false;
|
|
#if defined(__WXMSW__)
|
|
if (IsBOINCServiceInstalled()) bReturnValue = 1;
|
|
#elif defined(__WXMAC__)
|
|
if ( boinc_file_exists("/Library/LaunchDaemons/edu.berkeley.boinc.plist")) {
|
|
bReturnValue = NewStyleDaemon; // New-style daemon uses launchd
|
|
}
|
|
if (boinc_file_exists("/Library/StartupItems/boinc/boinc") ) {
|
|
bReturnValue = OldStyleDaemon; // Old-style daemon uses StartupItem
|
|
}
|
|
#endif
|
|
return bReturnValue;
|
|
}
|
|
|
|
|
|
bool CBOINCClientManager::IsBOINCCoreRunning() {
|
|
wxLogTrace(wxT("Function Start/End"), wxT("CBOINCClientManager::IsBOINCCoreRunning - Function Begin"));
|
|
|
|
int retval;
|
|
bool running = false;
|
|
HOST_INFO hostinfo;
|
|
RPC_CLIENT rpc;
|
|
|
|
#ifdef __WXMSW__
|
|
if (IsBOINCServiceInstalled()) {
|
|
running = (FALSE != IsBOINCServiceStarting()) || (FALSE != IsBOINCServiceRunning());
|
|
} else {
|
|
#endif
|
|
// If set up to run as a daemon, allow time for daemon to start up
|
|
for (int i=0; i<10; i++) {
|
|
retval = rpc.init("localhost"); // synchronous is OK since local
|
|
wxLogTrace(wxT("Function Status"), wxT("CBOINCClientManager::IsBOINCCoreRunning - Connecting to core client returned '%d'"), retval);
|
|
retval = rpc.get_host_info(hostinfo);
|
|
wxLogTrace(wxT("Function Status"), wxT("CBOINCClientManager::IsBOINCCoreRunning - Requesting host info... retval '%d'"), retval);
|
|
running = (retval == 0);
|
|
rpc.close();
|
|
if (running) break;
|
|
if (!IsBOINCConfiguredAsDaemon()) break;
|
|
wxSleep(1);
|
|
}
|
|
#ifdef __WXMSW__
|
|
}
|
|
#endif
|
|
|
|
wxLogTrace(wxT("Function Status"), wxT("CBOINCClientManager::IsBOINCCoreRunning - Returning '%d'"), retval);
|
|
wxLogTrace(wxT("Function Start/End"), wxT("CBOINCClientManager::IsBOINCCoreRunning - Function End"));
|
|
return running;
|
|
}
|
|
|
|
|
|
bool CBOINCClientManager::StartupBOINCCore() {
|
|
wxLogTrace(wxT("Function Start/End"), wxT("CMainDocument::StartupBOINCCore - Function Begin"));
|
|
|
|
bool bReturnValue = false;
|
|
wxString strExecute = wxEmptyString;
|
|
|
|
if (IsBOINCCoreRunning()) return true;
|
|
|
|
#if defined(__WXMSW__)
|
|
LPTSTR szExecute = NULL;
|
|
LPTSTR szDataDirectory = NULL;
|
|
|
|
if (IsBOINCConfiguredAsDaemon()) {
|
|
return (StartBOINCService());
|
|
}
|
|
|
|
// Append boinc.exe to the end of the strExecute string and get ready to rock
|
|
strExecute.Printf(
|
|
wxT("\"%s\\boinc.exe\" --redirectio --launched_by_manager %s"),
|
|
wxGetApp().GetRootDirectory().c_str(),
|
|
wxGetApp().GetArguments().c_str()
|
|
);
|
|
|
|
PROCESS_INFORMATION pi;
|
|
STARTUPINFO si;
|
|
BOOL bProcessStarted;
|
|
|
|
memset(&pi, 0, sizeof(pi));
|
|
memset(&si, 0, sizeof(si));
|
|
|
|
si.cb = sizeof(si);
|
|
si.dwFlags = STARTF_USESHOWWINDOW;
|
|
si.wShowWindow = SW_HIDE;
|
|
|
|
szExecute = (LPTSTR)strExecute.c_str();
|
|
if (wxGetApp().GetDataDirectory().empty()) {
|
|
szDataDirectory = NULL;
|
|
} else {
|
|
szDataDirectory = (LPTSTR)wxGetApp().GetDataDirectory().c_str();
|
|
}
|
|
|
|
wxLogTrace(wxT("Function Status"), wxT("CMainDocument::StartupBOINCCore - szExecute '%s'\n"), szExecute);
|
|
wxLogTrace(wxT("Function Status"), wxT("CMainDocument::StartupBOINCCore - szDataDirectory '%s'\n"), szDataDirectory);
|
|
|
|
bProcessStarted = CreateProcess(
|
|
NULL,
|
|
szExecute,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
CREATE_NEW_PROCESS_GROUP|CREATE_NO_WINDOW,
|
|
NULL,
|
|
szDataDirectory,
|
|
&si,
|
|
&pi
|
|
);
|
|
if (bProcessStarted) {
|
|
m_lBOINCCoreProcessId = pi.dwProcessId;
|
|
m_hBOINCCoreProcess = pi.hProcess;
|
|
}
|
|
|
|
#elif defined(__WXMAC__)
|
|
|
|
wxChar buf[1024];
|
|
wxChar *argv[5];
|
|
ProcessSerialNumber ourPSN;
|
|
FSRef ourFSRef;
|
|
OSErr err;
|
|
|
|
if (IsBOINCConfiguredAsDaemon() == NewStyleDaemon) {
|
|
system ("launchctl load /Library/LaunchDaemons/edu.berkeley.boinc.plist");
|
|
system ("launchctl start edu.berkeley.boinc");
|
|
bReturnValue = IsBOINCCoreRunning();
|
|
} else {
|
|
|
|
// Get the full path to core client inside this application's bundle
|
|
err = GetCurrentProcess (&ourPSN);
|
|
if (err == noErr) {
|
|
err = GetProcessBundleLocation(&ourPSN, &ourFSRef);
|
|
}
|
|
if (err == noErr) {
|
|
err = FSRefMakePath (&ourFSRef, (UInt8*)buf, sizeof(buf));
|
|
}
|
|
if (err == noErr) {
|
|
#if 0 // The Mac version of wxExecute(wxString& ...) crashes if there is a space in the path
|
|
strExecute = wxT("\"");
|
|
strExecute += wxT(buf);
|
|
strExecute += wxT("/Contents/Resources/boinc\" --redirectio --launched_by_manager");
|
|
m_lBOINCCoreProcessId = ::wxExecute(strExecute);
|
|
#else // Use wxExecute(wxChar **argv ...) instead of wxExecute(wxString& ...)
|
|
strcat(buf, "/Contents/Resources/boinc");
|
|
argv[0] = buf;
|
|
argv[1] = "--redirectio";
|
|
argv[2] = "--launched_by_manager";
|
|
argv[3] = NULL;
|
|
#ifdef SANDBOX
|
|
if (!g_use_sandbox) {
|
|
argv[3] = "--insecure";
|
|
argv[4] = NULL;
|
|
}
|
|
#endif
|
|
// Under wxMac-2.8.0, wxExecute starts a separate thread
|
|
// to wait for child's termination.
|
|
// That wxProcessTerminationThread uses a huge amount of processor
|
|
// time (about 11% of one CPU on 2GHz Intel Dual-Core Mac).
|
|
// m_lBOINCCoreProcessId = ::wxExecute(argv);
|
|
run_program(
|
|
"/Library/Application Support/BOINC Data",
|
|
buf, argv[3] ? 4 : 3, argv, 0.0, m_lBOINCCoreProcessId
|
|
);
|
|
#endif
|
|
} else {
|
|
buf[0] = '\0';
|
|
}
|
|
}
|
|
|
|
#else // Unix based systems
|
|
|
|
// Append boinc.exe to the end of the strExecute string and get ready to rock
|
|
strExecute = ::wxGetCwd() + wxT("/boinc --redirectio --launched_by_manager");
|
|
if (!g_use_sandbox) {
|
|
strExecute += wxT(" --insecure");
|
|
}
|
|
|
|
wxLogTrace(wxT("Function Status"), wxT("CMainDocument::StartupBOINCCore - szExecute '%s'\n"), strExecute.c_str());
|
|
wxLogTrace(wxT("Function Status"), wxT("CMainDocument::StartupBOINCCore - szDataDirectory '%s'\n"), ::wxGetCwd().c_str());
|
|
|
|
m_lBOINCCoreProcessId = ::wxExecute(strExecute);
|
|
|
|
#endif
|
|
|
|
if (0 != m_lBOINCCoreProcessId) {
|
|
m_bBOINCStartedByManager = true;
|
|
bReturnValue = true;
|
|
}
|
|
|
|
wxLogTrace(wxT("Function Start/End"), wxT("CMainDocument::StartupBOINCCore - Function End"));
|
|
return bReturnValue;
|
|
}
|
|
|
|
|
|
#if defined(__WXMSW__)
|
|
|
|
void CBOINCClientManager::ShutdownBOINCCore() {
|
|
wxLogTrace(wxT("Function Start/End"), wxT("CBOINCClientManager::ShutdownBOINCCore - Function Begin"));
|
|
|
|
CMainDocument* pDoc = wxGetApp().GetDocument();
|
|
wxInt32 iCount = 0;
|
|
DWORD dwExitCode = 0;
|
|
bool bClientQuit = false;
|
|
wxString strConnectedCompter = wxEmptyString;
|
|
wxString strPassword = wxEmptyString;
|
|
|
|
wxASSERT(pDoc);
|
|
wxASSERT(wxDynamicCast(pDoc, CMainDocument));
|
|
|
|
if (m_bBOINCStartedByManager) {
|
|
pDoc->GetConnectedComputerName(strConnectedCompter);
|
|
if (!pDoc->IsComputerNameLocal(strConnectedCompter)) {
|
|
RPC_CLIENT rpc;
|
|
if (!rpc.init("localhost")) {
|
|
pDoc->m_pNetworkConnection->GetLocalPassword(strPassword);
|
|
rpc.authorize((const char*)strPassword.mb_str());
|
|
if (GetExitCodeProcess(m_hBOINCCoreProcess, &dwExitCode)) {
|
|
if (STILL_ACTIVE == dwExitCode) {
|
|
rpc.quit();
|
|
for (iCount = 0; iCount <= 10; iCount++) {
|
|
if (!bClientQuit && GetExitCodeProcess(m_hBOINCCoreProcess, &dwExitCode)) {
|
|
if (STILL_ACTIVE != dwExitCode) {
|
|
wxLogTrace(wxT("Function Status"), wxT("CBOINCClientManager::ShutdownBOINCCore - (localhost) Application Exit Detected"));
|
|
bClientQuit = true;
|
|
break;
|
|
}
|
|
}
|
|
wxLogTrace(wxT("Function Status"), wxT("CBOINCClientManager::ShutdownBOINCCore - (localhost) Application Exit NOT Detected, Sleeping..."));
|
|
::wxSleep(1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
rpc.close();
|
|
} else {
|
|
if (GetExitCodeProcess(m_hBOINCCoreProcess, &dwExitCode)) {
|
|
if (STILL_ACTIVE == dwExitCode) {
|
|
pDoc->CoreClientQuit();
|
|
for (iCount = 0; iCount <= 10; iCount++) {
|
|
if (!bClientQuit && GetExitCodeProcess(m_hBOINCCoreProcess, &dwExitCode)) {
|
|
if (STILL_ACTIVE != dwExitCode) {
|
|
wxLogTrace(wxT("Function Status"), wxT("CBOINCClientManager::ShutdownBOINCCore - Application Exit Detected"));
|
|
bClientQuit = true;
|
|
break;
|
|
}
|
|
}
|
|
wxLogTrace(wxT("Function Status"), wxT("CBOINCClientManager::ShutdownBOINCCore - Application Exit NOT Detected, Sleeping..."));
|
|
::wxSleep(1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bClientQuit) {
|
|
::wxKill(m_lBOINCCoreProcessId);
|
|
}
|
|
m_lBOINCCoreProcessId = 0;
|
|
}
|
|
|
|
wxLogTrace(wxT("Function Start/End"), wxT("CBOINCClientManager::ShutdownBOINCCore - Function End"));
|
|
}
|
|
|
|
#elif defined(__WXMAC__)
|
|
|
|
static char * PersistentFGets(char *buf, size_t buflen, FILE *f) {
|
|
char *p = buf;
|
|
size_t len = buflen;
|
|
size_t datalen = 0;
|
|
|
|
*buf = '\0';
|
|
while (datalen < (buflen - 1)) {
|
|
fgets(p, len, f);
|
|
if (feof(f)) break;
|
|
if (ferror(f) && (errno != EINTR)) break;
|
|
if (strchr(buf, '\n')) break;
|
|
datalen = strlen(buf);
|
|
p = buf + datalen;
|
|
len -= datalen;
|
|
}
|
|
return (buf[0] ? buf : NULL);
|
|
}
|
|
|
|
bool CBOINCClientManager::ProcessExists(pid_t thePID)
|
|
{
|
|
FILE *f;
|
|
char buf[256];
|
|
pid_t aPID;
|
|
|
|
f = popen("ps -a -x -c -o pid,state", "r");
|
|
if (f == NULL)
|
|
return false;
|
|
|
|
while (PersistentFGets(buf, sizeof(buf), f)) {
|
|
aPID = atol(buf);
|
|
if (aPID == thePID) {
|
|
if (strchr(buf, 'Z')) // A 'zombie', stopped but waiting
|
|
break; // for us (its parent) to quit
|
|
pclose(f);
|
|
return true;
|
|
}
|
|
}
|
|
pclose(f);
|
|
return false;
|
|
}
|
|
|
|
// wxProcess::Exists and wxKill are unimplemented in WxMac-2.6.0
|
|
void CBOINCClientManager::ShutdownBOINCCore() {
|
|
CMainDocument* pDoc = wxGetApp().GetDocument();
|
|
wxInt32 iCount = 0;
|
|
wxString strConnectedCompter = wxEmptyString;
|
|
wxString strPassword = wxEmptyString;
|
|
|
|
wxASSERT(pDoc);
|
|
wxASSERT(wxDynamicCast(pDoc, CMainDocument));
|
|
|
|
if (m_bBOINCStartedByManager) {
|
|
pDoc->GetConnectedComputerName(strConnectedCompter);
|
|
if (!pDoc->IsComputerNameLocal(strConnectedCompter)) {
|
|
RPC_CLIENT rpc;
|
|
if (!rpc.init("localhost")) {
|
|
pDoc->m_pNetworkConnection->GetLocalPassword(strPassword);
|
|
rpc.authorize((const char*)strPassword.mb_str());
|
|
if (ProcessExists(m_lBOINCCoreProcessId)) {
|
|
rpc.quit();
|
|
for (iCount = 0; iCount <= 10; iCount++) {
|
|
if (!ProcessExists(m_lBOINCCoreProcessId))
|
|
return;
|
|
::wxSleep(1);
|
|
}
|
|
}
|
|
}
|
|
rpc.close();
|
|
} else {
|
|
if (ProcessExists(m_lBOINCCoreProcessId)) {
|
|
pDoc->CoreClientQuit();
|
|
for (iCount = 0; iCount <= 10; iCount++) {
|
|
if (!ProcessExists(m_lBOINCCoreProcessId))
|
|
return;
|
|
|
|
::wxSleep(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Client did not quit after 10 seconds so kill it
|
|
kill(m_lBOINCCoreProcessId, SIGKILL);
|
|
}
|
|
m_lBOINCCoreProcessId = 0;
|
|
}
|
|
|
|
#else
|
|
|
|
void CBOINCClientManager::ShutdownBOINCCore() {
|
|
CMainDocument* pDoc = wxGetApp().GetDocument();
|
|
wxInt32 iCount = 0;
|
|
bool bClientQuit = false;
|
|
wxString strConnectedCompter = wxEmptyString;
|
|
wxString strPassword = wxEmptyString;
|
|
|
|
wxASSERT(pDoc);
|
|
wxASSERT(wxDynamicCast(pDoc, CMainDocument));
|
|
|
|
if (m_bBOINCStartedByManager) {
|
|
pDoc->GetConnectedComputerName(strConnectedCompter);
|
|
if (!pDoc->IsComputerNameLocal(strConnectedCompter)) {
|
|
RPC_CLIENT rpc;
|
|
if (!rpc.init("localhost")) {
|
|
pDoc->m_pNetworkConnection->GetLocalPassword(strPassword);
|
|
rpc.authorize((const char*)strPassword.mb_str());
|
|
if (wxProcess::Exists(m_lBOINCCoreProcessId)) {
|
|
rpc.quit();
|
|
for (iCount = 0; iCount <= 10; iCount++) {
|
|
if (!bClientQuit && !wxProcess::Exists(m_lBOINCCoreProcessId)) {
|
|
bClientQuit = true;
|
|
break;
|
|
}
|
|
::wxSleep(1);
|
|
}
|
|
}
|
|
}
|
|
rpc.close();
|
|
} else {
|
|
if (wxProcess::Exists(m_lBOINCCoreProcessId)) {
|
|
pDoc->CoreClientQuit();
|
|
for (iCount = 0; iCount <= 10; iCount++) {
|
|
if (!bClientQuit && !wxProcess::Exists(m_lBOINCCoreProcessId)) {
|
|
bClientQuit = true;
|
|
break;
|
|
}
|
|
::wxSleep(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bClientQuit) {
|
|
::wxKill(m_lBOINCCoreProcessId);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|