- made windows gui service only (removed desktop mode).

- changed watchdog to only launch if it has a command.
This commit is contained in:
Nick Bolton 2013-10-15 15:46:02 +00:00
parent 8040f1c5a3
commit 658a3e3e8f
11 changed files with 92 additions and 245 deletions

View File

@ -364,6 +364,9 @@
</item> </item>
<item> <item>
<widget class="QPushButton" name="m_pButtonApply"> <widget class="QPushButton" name="m_pButtonApply">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text"> <property name="text">
<string>&amp;Apply</string> <string>&amp;Apply</string>
</property> </property>

View File

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>368</width> <width>368</width>
<height>485</height> <height>354</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -89,30 +89,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="0">
<widget class="QLabel" name="m_pLabel_22">
<property name="text">
<string>&amp;Process mode:</string>
</property>
<property name="buddy">
<cstring>m_pComboProcessMode</cstring>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="m_pComboProcessMode">
<item>
<property name="text">
<string>Service</string>
</property>
</item>
<item>
<property name="text">
<string>Desktop (legacy)</string>
</property>
</item>
</widget>
</item>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="m_pLabel_27"> <widget class="QLabel" name="m_pLabel_27">
<property name="sizePolicy"> <property name="sizePolicy">
@ -141,36 +117,6 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item>
<widget class="QGroupBox" name="m_pGroupUserInterface">
<property name="title">
<string>&amp;Startup</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QCheckBox" name="m_pCheckBoxAutoStart">
<property name="text">
<string>&amp;Start Synergy after logging in</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="m_pCheckBoxAutoConnect">
<property name="text">
<string>&amp;Automatically start server/client</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="m_pCheckBoxAutoHide">
<property name="text">
<string>&amp;Hide when server/client starts</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item> <item>
<widget class="QGroupBox" name="m_pGroupCrypto"> <widget class="QGroupBox" name="m_pGroupCrypto">
<property name="enabled"> <property name="enabled">
@ -355,10 +301,6 @@
<tabstop>m_pLineEditScreenName</tabstop> <tabstop>m_pLineEditScreenName</tabstop>
<tabstop>m_pSpinBoxPort</tabstop> <tabstop>m_pSpinBoxPort</tabstop>
<tabstop>m_pLineEditInterface</tabstop> <tabstop>m_pLineEditInterface</tabstop>
<tabstop>m_pComboProcessMode</tabstop>
<tabstop>m_pCheckBoxAutoStart</tabstop>
<tabstop>m_pCheckBoxAutoConnect</tabstop>
<tabstop>m_pCheckBoxAutoHide</tabstop>
<tabstop>m_pLineEditCryptoPass</tabstop> <tabstop>m_pLineEditCryptoPass</tabstop>
<tabstop>m_pComboLogLevel</tabstop> <tabstop>m_pComboLogLevel</tabstop>
<tabstop>m_pCheckBoxLogToFile</tabstop> <tabstop>m_pCheckBoxLogToFile</tabstop>

View File

@ -47,14 +47,10 @@ static const char* logLevelNames[] =
AppConfig::AppConfig(QSettings* settings) : AppConfig::AppConfig(QSettings* settings) :
m_pSettings(settings), m_pSettings(settings),
m_AutoConnect(false),
m_ScreenName(), m_ScreenName(),
m_Port(24800), m_Port(24800),
m_Interface(), m_Interface(),
m_LogLevel(0), m_LogLevel(0),
m_AutoStart(false),
m_AutoHide(false),
m_AutoStartPrompt(false),
m_WizardLastRun(0), m_WizardLastRun(0),
m_CryptoPass(), m_CryptoPass(),
m_ProcessMode(DEFAULT_PROCESS_MODE) m_ProcessMode(DEFAULT_PROCESS_MODE)
@ -102,62 +98,15 @@ QString AppConfig::logLevelText() const
return logLevelNames[logLevel()]; return logLevelNames[logLevel()];
} }
void AppConfig::setAutoStart(bool b)
{
m_AutoStart = b;
// always create or delete the links/files/entries even if they exist already,
// in case it was broken.
#if defined(Q_OS_LINUX)
QString desktopFileName("synergy.desktop");
QString desktopFilePath("/usr/share/applications/" + desktopFileName);
QString autoStartPath(QDir::homePath() + "/.config/autostart/" + desktopFileName);
if (b)
{
QFile::link(desktopFilePath, autoStartPath);
}
else
{
QFile::remove(autoStartPath);
}
#elif defined(Q_OS_WIN)
QSettings settings("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat);
QString path("Synergy");
if (b)
{
settings.setValue(path, QCoreApplication::applicationFilePath());
}
else
{
settings.remove(path);
}
settings.sync();
#endif
// TODO: mac os x auto start
}
void AppConfig::loadSettings() void AppConfig::loadSettings()
{ {
m_AutoConnect = settings().value("autoConnect", false).toBool();
m_ScreenName = settings().value("screenName", QHostInfo::localHostName()).toString(); m_ScreenName = settings().value("screenName", QHostInfo::localHostName()).toString();
m_Port = settings().value("port", 24800).toInt(); m_Port = settings().value("port", 24800).toInt();
m_Interface = settings().value("interface").toString(); m_Interface = settings().value("interface").toString();
m_LogLevel = settings().value("logLevel", 3).toInt(); // level 3: INFO m_LogLevel = settings().value("logLevel", 3).toInt(); // level 3: INFO
m_LogToFile = settings().value("logToFile", false).toBool(); m_LogToFile = settings().value("logToFile", false).toBool();
m_LogFilename = settings().value("logFilename", synergyLogDir() + "synergy.log").toString(); m_LogFilename = settings().value("logFilename", synergyLogDir() + "synergy.log").toString();
m_AutoStart = settings().value("autoStart", false).toBool();
m_AutoHide = settings().value("autoHide", true).toBool();
m_AutoStartPrompt = settings().value("autoStartPrompt", true).toBool();
m_WizardLastRun = settings().value("wizardLastRun", 0).toInt(); m_WizardLastRun = settings().value("wizardLastRun", 0).toInt();
m_ProcessMode = (ProcessMode)settings().value("processMode2", DEFAULT_PROCESS_MODE).toInt();
m_CryptoPass = settings().value("cryptoPass", "").toString(); m_CryptoPass = settings().value("cryptoPass", "").toString();
m_CryptoEnabled = settings().value("cryptoEnabled", false).toBool(); m_CryptoEnabled = settings().value("cryptoEnabled", false).toBool();
m_Language = settings().value("language", QLocale::system().name()).toString(); m_Language = settings().value("language", QLocale::system().name()).toString();
@ -167,18 +116,13 @@ void AppConfig::loadSettings()
void AppConfig::saveSettings() void AppConfig::saveSettings()
{ {
settings().setValue("autoConnect", m_AutoConnect);
settings().setValue("screenName", m_ScreenName); settings().setValue("screenName", m_ScreenName);
settings().setValue("port", m_Port); settings().setValue("port", m_Port);
settings().setValue("interface", m_Interface); settings().setValue("interface", m_Interface);
settings().setValue("logLevel", m_LogLevel); settings().setValue("logLevel", m_LogLevel);
settings().setValue("logToFile", m_LogToFile); settings().setValue("logToFile", m_LogToFile);
settings().setValue("logFilename", m_LogFilename); settings().setValue("logFilename", m_LogFilename);
settings().setValue("autoStart", m_AutoStart);
settings().setValue("autoHide", m_AutoHide);
settings().setValue("autoStartPrompt", m_AutoStartPrompt);
settings().setValue("wizardLastRun", kWizardVersion); settings().setValue("wizardLastRun", kWizardVersion);
settings().setValue("processMode2", m_ProcessMode);
settings().setValue("cryptoPass", m_CryptoPass); settings().setValue("cryptoPass", m_CryptoPass);
settings().setValue("cryptoEnabled", m_CryptoEnabled); settings().setValue("cryptoEnabled", m_CryptoEnabled);
settings().setValue("language", m_Language); settings().setValue("language", m_Language);

View File

@ -53,7 +53,6 @@ class AppConfig
~AppConfig(); ~AppConfig();
public: public:
bool autoConnect() const { return m_AutoConnect; }
const QString& screenName() const { return m_ScreenName; } const QString& screenName() const { return m_ScreenName; }
int port() const { return m_Port; } int port() const { return m_Port; }
const QString& interface() const { return m_Interface; } const QString& interface() const { return m_Interface; }
@ -61,9 +60,6 @@ class AppConfig
bool logToFile() const { return m_LogToFile; } bool logToFile() const { return m_LogToFile; }
const QString& logFilename() const { return m_LogFilename; } const QString& logFilename() const { return m_LogFilename; }
QString logLevelText() const; QString logLevelText() const;
bool autoStart() const { return m_AutoStart; }
bool autoHide() const { return m_AutoHide; }
bool autoStartPrompt() const { return m_AutoStartPrompt; }
const QString& cryptoPass() const { return m_CryptoPass; } const QString& cryptoPass() const { return m_CryptoPass; }
bool cryptoEnabled() const { return m_CryptoEnabled; } bool cryptoEnabled() const { return m_CryptoEnabled; }
QString cryptoModeString() const; QString cryptoModeString() const;
@ -84,18 +80,13 @@ class AppConfig
protected: protected:
QSettings& settings() { return *m_pSettings; } QSettings& settings() { return *m_pSettings; }
void setAutoConnect(bool b) { m_AutoConnect = b; }
void setScreenName(const QString& s) { m_ScreenName = s; } void setScreenName(const QString& s) { m_ScreenName = s; }
void setPort(int i) { m_Port = i; } void setPort(int i) { m_Port = i; }
void setInterface(const QString& s) { m_Interface = s; } void setInterface(const QString& s) { m_Interface = s; }
void setLogLevel(int i) { m_LogLevel = i; } void setLogLevel(int i) { m_LogLevel = i; }
void setLogToFile(bool b) { m_LogToFile = b; } void setLogToFile(bool b) { m_LogToFile = b; }
void setLogFilename(const QString& s) { m_LogFilename = s; } void setLogFilename(const QString& s) { m_LogFilename = s; }
void setAutoStart(bool b);
void setAutoHide(bool b) { m_AutoHide = b; }
void setAutoStartPrompt(bool b) { m_AutoStartPrompt = b; }
void setCryptoEnabled(bool b) { m_CryptoEnabled = b; } void setCryptoEnabled(bool b) { m_CryptoEnabled = b; }
void setProcessMode(ProcessMode p) { m_ProcessMode = p; }
void setWizardHasRun() { m_WizardLastRun = kWizardVersion; } void setWizardHasRun() { m_WizardLastRun = kWizardVersion; }
void setLanguage(const QString language) { m_Language = language; } void setLanguage(const QString language) { m_Language = language; }
void setPremiumEmail(const QString premiumEmail) { m_PremiumEmail = premiumEmail; } void setPremiumEmail(const QString premiumEmail) { m_PremiumEmail = premiumEmail; }
@ -108,16 +99,12 @@ class AppConfig
private: private:
QSettings* m_pSettings; QSettings* m_pSettings;
bool m_AutoConnect;
QString m_ScreenName; QString m_ScreenName;
int m_Port; int m_Port;
QString m_Interface; QString m_Interface;
int m_LogLevel; int m_LogLevel;
bool m_LogToFile; bool m_LogToFile;
QString m_LogFilename; QString m_LogFilename;
bool m_AutoStart;
bool m_AutoHide;
bool m_AutoStartPrompt;
int m_WizardLastRun; int m_WizardLastRun;
bool m_CryptoEnabled; bool m_CryptoEnabled;
QString m_CryptoPass; QString m_CryptoPass;

View File

@ -119,8 +119,6 @@ MainWindow::~MainWindow()
void MainWindow::start(bool firstRun) void MainWindow::start(bool firstRun)
{ {
onModeChanged(!firstRun && appConfig().autoConnect(), false);
createTrayIcon(); createTrayIcon();
// always show. auto-hide only happens when we have a connection. // always show. auto-hide only happens when we have a connection.
@ -131,8 +129,6 @@ void MainWindow::start(bool firstRun)
void MainWindow::onModeChanged(bool startDesktop, bool applyService) void MainWindow::onModeChanged(bool startDesktop, bool applyService)
{ {
refreshApplyButton();
if (appConfig().processMode() == Service) if (appConfig().processMode() == Service)
{ {
// form is always enabled in service mode. // form is always enabled in service mode.
@ -158,11 +154,6 @@ void MainWindow::onModeChanged(bool startDesktop, bool applyService)
m_pElevateCheckBox->setEnabled(appConfig().processMode() == Service); m_pElevateCheckBox->setEnabled(appConfig().processMode() == Service);
} }
void MainWindow::refreshApplyButton()
{
m_pButtonApply->setEnabled(appConfig().processMode() == Service);
}
void MainWindow::setStatus(const QString &status) void MainWindow::setStatus(const QString &status)
{ {
m_pStatusLabel->setText(status); m_pStatusLabel->setText(status);
@ -282,6 +273,7 @@ void MainWindow::setIcon(qSynergyState state)
void MainWindow::trayActivated(QSystemTrayIcon::ActivationReason reason) void MainWindow::trayActivated(QSystemTrayIcon::ActivationReason reason)
{ {
#ifndef Q_OS_WIN
if (reason == QSystemTrayIcon::DoubleClick) if (reason == QSystemTrayIcon::DoubleClick)
{ {
if (isVisible()) if (isVisible())
@ -294,6 +286,7 @@ void MainWindow::trayActivated(QSystemTrayIcon::ActivationReason reason)
activateWindow(); activateWindow();
} }
} }
#endif
} }
void MainWindow::logOutput() void MainWindow::logOutput()
@ -356,13 +349,6 @@ void MainWindow::updateStateFromLogLine(const QString &line)
line.contains("connected to server")) line.contains("connected to server"))
{ {
setSynergyState(synergyConnected); setSynergyState(synergyConnected);
// only hide once after each new connection.
if (!m_AlreadyHidden && appConfig().autoHide())
{
hide();
m_AlreadyHidden = true;
}
} }
} }
@ -646,12 +632,14 @@ void MainWindow::setSynergyState(qSynergyState state)
disconnect (m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStartSynergy, SLOT(trigger())); disconnect (m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStartSynergy, SLOT(trigger()));
connect (m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStopSynergy, SLOT(trigger())); connect (m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStopSynergy, SLOT(trigger()));
m_pButtonToggleStart->setText(tr("&Stop")); m_pButtonToggleStart->setText(tr("&Stop"));
m_pButtonApply->setEnabled((appConfig().processMode() == Service));
} }
else else
{ {
disconnect (m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStopSynergy, SLOT(trigger())); disconnect (m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStopSynergy, SLOT(trigger()));
connect (m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStartSynergy, SLOT(trigger())); connect (m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStartSynergy, SLOT(trigger()));
m_pButtonToggleStart->setText(tr("&Start")); m_pButtonToggleStart->setText(tr("&Start"));
m_pButtonApply->setEnabled(false);
} }
bool connected = state == synergyConnected; bool connected = state == synergyConnected;
@ -693,9 +681,9 @@ void MainWindow::setFormEnabled(bool enabled)
void MainWindow::setVisible(bool visible) void MainWindow::setVisible(bool visible)
{ {
QMainWindow::setVisible(visible);
m_pActionMinimize->setEnabled(visible); m_pActionMinimize->setEnabled(visible);
m_pActionRestore->setEnabled(!visible); m_pActionRestore->setEnabled(!visible);
QMainWindow::setVisible(visible);
#if MAC_OS_X_VERSION_10_7 #if MAC_OS_X_VERSION_10_7
// dock hide only supported on lion :( // dock hide only supported on lion :(

View File

@ -114,7 +114,6 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase
void logOutput(); void logOutput();
void logError(); void logError();
void updateFound(const QString& version); void updateFound(const QString& version);
void refreshApplyButton();
protected: protected:
QSettings& settings() { return m_Settings; } QSettings& settings() { return m_Settings; }

View File

@ -34,16 +34,12 @@ SettingsDialog::SettingsDialog(QWidget* parent, AppConfig& config) :
m_Locale.fillLanguageComboBox(m_pComboLanguage); m_Locale.fillLanguageComboBox(m_pComboLanguage);
m_pCheckBoxAutoConnect->setChecked(appConfig().autoConnect());
m_pLineEditScreenName->setText(appConfig().screenName()); m_pLineEditScreenName->setText(appConfig().screenName());
m_pSpinBoxPort->setValue(appConfig().port()); m_pSpinBoxPort->setValue(appConfig().port());
m_pLineEditInterface->setText(appConfig().interface()); m_pLineEditInterface->setText(appConfig().interface());
m_pComboProcessMode->setCurrentIndex(appConfig().processMode());
m_pComboLogLevel->setCurrentIndex(appConfig().logLevel()); m_pComboLogLevel->setCurrentIndex(appConfig().logLevel());
m_pCheckBoxLogToFile->setChecked(appConfig().logToFile()); m_pCheckBoxLogToFile->setChecked(appConfig().logToFile());
m_pLineEditLogFilename->setText(appConfig().logFilename()); m_pLineEditLogFilename->setText(appConfig().logFilename());
m_pCheckBoxAutoStart->setChecked(appConfig().autoStart());
m_pCheckBoxAutoHide->setChecked(appConfig().autoHide());
m_pCheckBoxEnableCrypto->setChecked(appConfig().cryptoEnabled()); m_pCheckBoxEnableCrypto->setChecked(appConfig().cryptoEnabled());
setIndexFromItemData(m_pComboLanguage, appConfig().language()); setIndexFromItemData(m_pComboLanguage, appConfig().language());
if (appConfig().cryptoEnabled()) if (appConfig().cryptoEnabled())
@ -66,16 +62,12 @@ void SettingsDialog::accept()
return; return;
} }
appConfig().setAutoConnect(m_pCheckBoxAutoConnect->isChecked());
appConfig().setScreenName(m_pLineEditScreenName->text()); appConfig().setScreenName(m_pLineEditScreenName->text());
appConfig().setPort(m_pSpinBoxPort->value()); appConfig().setPort(m_pSpinBoxPort->value());
appConfig().setInterface(m_pLineEditInterface->text()); appConfig().setInterface(m_pLineEditInterface->text());
appConfig().setProcessMode((ProcessMode)m_pComboProcessMode->currentIndex());
appConfig().setLogLevel(m_pComboLogLevel->currentIndex()); appConfig().setLogLevel(m_pComboLogLevel->currentIndex());
appConfig().setLogToFile(m_pCheckBoxLogToFile->isChecked()); appConfig().setLogToFile(m_pCheckBoxLogToFile->isChecked());
appConfig().setLogFilename(m_pLineEditLogFilename->text()); appConfig().setLogFilename(m_pLineEditLogFilename->text());
appConfig().setAutoStart(m_pCheckBoxAutoStart->isChecked());
appConfig().setAutoHide(m_pCheckBoxAutoHide->isChecked());
appConfig().setCryptoEnabled(cryptoEnabled); appConfig().setCryptoEnabled(cryptoEnabled);
appConfig().setCryptoPass(cryptoPass); appConfig().setCryptoPass(cryptoPass);
appConfig().setLanguage(m_pComboLanguage->itemData(m_pComboLanguage->currentIndex()).toString()); appConfig().setLanguage(m_pComboLanguage->itemData(m_pComboLanguage->currentIndex()).toString());
@ -98,14 +90,12 @@ void SettingsDialog::changeEvent(QEvent* event)
case QEvent::LanguageChange: case QEvent::LanguageChange:
{ {
int logLevelIndex = m_pComboLogLevel->currentIndex(); int logLevelIndex = m_pComboLogLevel->currentIndex();
int processModeIndex = m_pComboProcessMode->currentIndex();
m_pComboLanguage->blockSignals(true); m_pComboLanguage->blockSignals(true);
retranslateUi(this); retranslateUi(this);
m_pComboLanguage->blockSignals(false); m_pComboLanguage->blockSignals(false);
m_pComboLogLevel->setCurrentIndex(logLevelIndex); m_pComboLogLevel->setCurrentIndex(logLevelIndex);
m_pComboProcessMode->setCurrentIndex(processModeIndex);
break; break;
} }

View File

@ -50,7 +50,9 @@ int main(int argc, char* argv[])
if (!waitForTray()) if (!waitForTray())
return -1; return -1;
#ifndef Q_OS_WIN
QApplication::setQuitOnLastWindowClosed(false); QApplication::setQuitOnLastWindowClosed(false);
#endif
QSettings settings; QSettings settings;
AppConfig appConfig(&settings); AppConfig appConfig(&settings);

View File

@ -54,8 +54,8 @@ CMSWindowsWatchdog::CMSWindowsWatchdog(
m_ipcServer(ipcServer), m_ipcServer(ipcServer),
m_ipcLogOutputter(ipcLogOutputter), m_ipcLogOutputter(ipcLogOutputter),
m_elevateProcess(false), m_elevateProcess(false),
m_launched(false), m_processFailures(0),
m_failures(0) m_processRunning(false)
{ {
} }
@ -165,56 +165,70 @@ CMSWindowsWatchdog::mainLoop(void*)
ZeroMemory(&m_processInfo, sizeof(PROCESS_INFORMATION)); ZeroMemory(&m_processInfo, sizeof(PROCESS_INFORMATION));
while (m_monitoring) { while (m_monitoring) {
try {
// relaunch if the process was running but has stopped unexpectedly.
if ((m_launched && !isProcessRunning()) || m_session.hasChanged() || m_commandChanged) { if (m_processRunning && getCommand().empty()) {
LOG((CLOG_INFO "process started but command is empty, shutting down"));
std::string command = getCommand();
if (command.empty()) {
// this appears on first launch when the user hasn't configured
// anything yet, so don't show it as a warning, only show it as
// debug to devs to let them know why nothing happened.
LOG((CLOG_DEBUG "nothing to launch, no command specified."));
shutdownExistingProcesses(); shutdownExistingProcesses();
m_processRunning = false;
continue; continue;
} }
try { if (m_processFailures != 0) {
startProcess(command); // increasing backoff period, maximum of 10 seconds.
int timeout = (m_processFailures * 2) < 10 ? (m_processFailures * 2) : 10;
LOG((CLOG_INFO "backing off, wait=%ds, failures=%d", timeout, m_processFailures));
ARCH->sleep(timeout);
} }
catch (XArch& e) {
LOG((CLOG_ERR "failed to launch, error: %s", e.what().c_str())); if (!getCommand().empty() && ((m_processFailures != 0) || m_session.hasChanged() || m_commandChanged)) {
m_launched = false; startProcess();
continue;
} }
catch (XSynergy& e) {
LOG((CLOG_ERR "failed to launch, error: %s", e.what())); if (m_processRunning && !isProcessActive()) {
m_launched = false;
continue; m_processFailures++;
m_processRunning = false;
LOG((CLOG_WARN "detected application not running, pid=%d",
m_processInfo.dwProcessId));
} }
}
if (sendSasFunc != NULL) { if (sendSasFunc != NULL) {
HANDLE sendSasEvent = CreateEvent(NULL, FALSE, FALSE, "Global\\SendSAS"); HANDLE sendSasEvent = CreateEvent(NULL, FALSE, FALSE, "Global\\SendSAS");
if (sendSasEvent != NULL) { if (sendSasEvent != NULL) {
// use SendSAS event to wait for next session (timeout 1 second). // use SendSAS event to wait for next session (timeout 1 second).
if (WaitForSingleObject(sendSasEvent, 1000) == WAIT_OBJECT_0) { if (WaitForSingleObject(sendSasEvent, 1000) == WAIT_OBJECT_0) {
LOG((CLOG_DEBUG "calling SendSAS")); LOG((CLOG_DEBUG "calling SendSAS"));
sendSasFunc(FALSE); sendSasFunc(FALSE);
}
CloseHandle(sendSasEvent);
continue;
} }
CloseHandle(sendSasEvent);
continue;
} }
}
// if the sas event failed, wait by sleeping. // if the sas event failed, wait by sleeping.
ARCH->sleep(1); ARCH->sleep(1);
}
catch (XArch& e) {
LOG((CLOG_ERR "failed to launch, error: %s", e.what().c_str()));
m_processFailures++;
m_processRunning = false;
continue;
}
catch (XSynergy& e) {
LOG((CLOG_ERR "failed to launch, error: %s", e.what()));
m_processFailures++;
m_processRunning = false;
continue;
}
} }
if (m_launched) { if (m_processRunning) {
LOG((CLOG_DEBUG "terminated running process on exit")); LOG((CLOG_DEBUG "terminated running process on exit"));
shutdownProcess(m_processInfo.hProcess, m_processInfo.dwProcessId, 20); shutdownProcess(m_processInfo.hProcess, m_processInfo.dwProcessId, 20);
} }
@ -223,47 +237,26 @@ CMSWindowsWatchdog::mainLoop(void*)
} }
bool bool
CMSWindowsWatchdog::isProcessRunning() CMSWindowsWatchdog::isProcessActive()
{ {
bool running; DWORD exitCode;
if (m_launched) { GetExitCodeProcess(m_processInfo.hProcess, &exitCode);
return exitCode == STILL_ACTIVE;
DWORD exitCode;
GetExitCodeProcess(m_processInfo.hProcess, &exitCode);
running = (exitCode == STILL_ACTIVE);
if (!running && !m_command.empty()) {
m_failures++;
LOG((CLOG_INFO
"detected application not running, pid=%d, failures=%d",
m_processInfo.dwProcessId, m_failures));
// increasing backoff period, maximum of 10 seconds.
int timeout = (m_failures * 2) < 10 ? (m_failures * 2) : 10;
LOG((CLOG_DEBUG "waiting, backoff period is %d seconds", timeout));
ARCH->sleep(timeout);
// double check, in case process started after we waited.
GetExitCodeProcess(m_processInfo.hProcess, &exitCode);
running = (exitCode == STILL_ACTIVE);
}
else {
// reset failures when running.
m_failures = 0;
}
}
return running;
} }
void void
CMSWindowsWatchdog::startProcess(std::string& command) CMSWindowsWatchdog::startProcess()
{ {
if (m_command.empty()) {
throw XMSWindowsWatchdogError("cannot start process, command is empty");
}
m_commandChanged = false; m_commandChanged = false;
if (m_launched) { if (m_processRunning) {
LOG((CLOG_DEBUG "closing existing process to make way for new one")); LOG((CLOG_DEBUG "closing existing process to make way for new one"));
shutdownProcess(m_processInfo.hProcess, m_processInfo.dwProcessId, 20); shutdownProcess(m_processInfo.hProcess, m_processInfo.dwProcessId, 20);
m_launched = false; m_processRunning = false;
} }
m_session.updateActiveSession(); m_session.updateActiveSession();
@ -299,7 +292,7 @@ CMSWindowsWatchdog::startProcess(std::string& command)
// re-launch in current active user session // re-launch in current active user session
LOG((CLOG_INFO "starting new process")); LOG((CLOG_INFO "starting new process"));
BOOL createRet = CreateProcessAsUser( BOOL createRet = CreateProcessAsUser(
userToken, NULL, LPSTR(command.c_str()), userToken, NULL, LPSTR(m_command.c_str()),
&sa, NULL, TRUE, creationFlags, &sa, NULL, TRUE, creationFlags,
environment, NULL, &si, &m_processInfo); environment, NULL, &si, &m_processInfo);
@ -311,9 +304,11 @@ CMSWindowsWatchdog::startProcess(std::string& command)
throw XArch(new XArchEvalWindows); throw XArch(new XArchEvalWindows);
} }
else { else {
m_processRunning = true;
m_processFailures = 0;
LOG((CLOG_DEBUG "started process, session=%i, command=%s", LOG((CLOG_DEBUG "started process, session=%i, command=%s",
m_session.getActiveSessionId(), command.c_str())); m_session.getActiveSessionId(), m_command.c_str()));
m_launched = true;
} }
} }
@ -470,4 +465,5 @@ CMSWindowsWatchdog::shutdownExistingProcesses()
} }
CloseHandle(snapshot); CloseHandle(snapshot);
m_processRunning = false;
} }

View File

@ -49,8 +49,8 @@ private:
void shutdownExistingProcesses(); void shutdownExistingProcesses();
HANDLE duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTES security); HANDLE duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTES security);
HANDLE getUserToken(LPSECURITY_ATTRIBUTES security); HANDLE getUserToken(LPSECURITY_ATTRIBUTES security);
void startProcess(std::string& command); void startProcess();
bool isProcessRunning(); bool isProcessActive();
void sendSas(); void sendSas();
private: private:
@ -66,9 +66,9 @@ private:
CIpcLogOutputter& m_ipcLogOutputter; CIpcLogOutputter& m_ipcLogOutputter;
bool m_elevateProcess; bool m_elevateProcess;
CMSWindowsSession m_session; CMSWindowsSession m_session;
bool m_launched;
PROCESS_INFORMATION m_processInfo; PROCESS_INFORMATION m_processInfo;
int m_failures; int m_processFailures;
bool m_processRunning;
}; };
//! Relauncher error //! Relauncher error

View File

@ -45,6 +45,7 @@
#include "CMSWindowsScreen.h" #include "CMSWindowsScreen.h"
#include "CMSWindowsDebugOutputter.h" #include "CMSWindowsDebugOutputter.h"
#include "CMSWindowsWatchdog.h" #include "CMSWindowsWatchdog.h"
#include "CMSWindowsEventQueueBuffer.h"
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <Windows.h> #include <Windows.h>
@ -191,10 +192,7 @@ CDaemonApp::mainLoop(bool logToFile)
try try
{ {
DAEMON_RUNNING(true); DAEMON_RUNNING(true);
/*while (true)
{
}*/
if (logToFile) if (logToFile)
CLOG->insert(new CFileLogOutputter(logPath().c_str())); CLOG->insert(new CFileLogOutputter(logPath().c_str()));
@ -208,22 +206,21 @@ CDaemonApp::mainLoop(bool logToFile)
// send logging to gui via ipc, log system adopts outputter. // send logging to gui via ipc, log system adopts outputter.
m_ipcLogOutputter = new CIpcLogOutputter(*m_ipcServer); m_ipcLogOutputter = new CIpcLogOutputter(*m_ipcServer);
CLOG->insert(m_ipcLogOutputter); CLOG->insert(m_ipcLogOutputter);
#if SYSAPI_WIN32 #if SYSAPI_WIN32
m_watchdog = new CMSWindowsWatchdog(false, *m_ipcServer, *m_ipcLogOutputter); m_watchdog = new CMSWindowsWatchdog(false, *m_ipcServer, *m_ipcLogOutputter);
#endif #endif
m_events->adoptHandler( m_events->adoptHandler(
m_events->forCIpcServer().messageReceived(), m_ipcServer, m_events->forCIpcServer().messageReceived(), m_ipcServer,
new TMethodEventJob<CDaemonApp>(this, &CDaemonApp::handleIpcMessage)); new TMethodEventJob<CDaemonApp>(this, &CDaemonApp::handleIpcMessage));
m_ipcServer->listen(); m_ipcServer->listen();
#if SYSAPI_WIN32 #if SYSAPI_WIN32
// HACK: create a dummy screen, which can handle system events
// (such as a stop request from the service controller). // install the platform event queue to handle service stop events.
CMSWindowsScreen::init(CArchMiscWindows::instanceWin32()); m_events->adoptBuffer(new CMSWindowsEventQueueBuffer(m_events));
CScreen dummyScreen(new CMSWindowsScreen(false, true, false, m_events), m_events);
CString command = ARCH->setting("Command"); CString command = ARCH->setting("Command");
bool elevate = ARCH->setting("Elevate") == "1"; bool elevate = ARCH->setting("Elevate") == "1";
@ -234,7 +231,6 @@ CDaemonApp::mainLoop(bool logToFile)
m_watchdog->startAsync(); m_watchdog->startAsync();
#endif #endif
m_events->loop(); m_events->loop();
#if SYSAPI_WIN32 #if SYSAPI_WIN32
@ -248,7 +244,7 @@ CDaemonApp::mainLoop(bool logToFile)
CLOG->remove(m_ipcLogOutputter); CLOG->remove(m_ipcLogOutputter);
delete m_ipcLogOutputter; delete m_ipcLogOutputter;
delete m_ipcServer; delete m_ipcServer;
DAEMON_RUNNING(false); DAEMON_RUNNING(false);
} }
catch (XArch& e) { catch (XArch& e) {