Skip to content
Permalink
Browse files

Add self-restart capability to client

For some option changes a client restart is required
to fully apply the changes. This patch enabled Mumble
to restart itself. This is accomplished by adding a
special MUMBLE_EXIT_CODE_RESTART exit code that is
cought right before the application terminates. Mumble
then uses available session information to launch
another instance of itself right before it exits. As
this happens after the vast majority of cleanup multiple
client restrictions and other resource contention issues
do not come into play.

Launching another client deviates from the usually
recommended way of not exiting the process but simply
doing a re-initialization of the application after the
cleanup. With Mumble this is tricky as we have some
objects for which we do not control the lifetime after
we initialized them once and others might be managed
sloppily as the design never expected to have to
re-initialize. We should strive to clean up these
weaknesses in resource management but for now the
approach taken here works around them.
  • Loading branch information...
hacst committed Jun 12, 2015
1 parent 7fbe61e commit c431d376f8a6f9723380e909f0b38a72771e11e3
Showing with 58 additions and 2 deletions.
  1. +3 −0 src/mumble/Global.h
  2. +19 −0 src/mumble/ServerHandler.cpp
  3. +3 −0 src/mumble/ServerHandler.h
  4. +33 −2 src/mumble/main.cpp
@@ -138,6 +138,9 @@ class DeferInit {
static void run_destroyers();
};

/// Special exit code which causes mumble to restart itself. The outward facing return code with be 0
const int MUMBLE_EXIT_CODE_RESTART = 64738;

// -Wshadow is bugged. If an inline function of a class uses a variable or
// parameter named 'g', that will generate a warning even if the class header
// is included long before this definition.
@@ -46,6 +46,7 @@
#include "RichTextEditor.h"
#include "SSL.h"
#include "User.h"
#include "Net.h"

ServerHandlerMessageEvent::ServerHandlerMessageEvent(const QByteArray &msg, unsigned int mtype, bool flush) : QEvent(static_cast<QEvent::Type>(SERVERSEND_EVENT)) {
qbaMsg = msg;
@@ -848,3 +849,21 @@ void ServerHandler::announceRecordingState(bool recording) {
sendMessage(mpus);
}

QUrl ServerHandler::getServerURL(bool withPassword) const {
QUrl url;

url.setScheme(QLatin1String("mumble"));
url.setHost(qsHostName);
if (usPort != DEFAULT_MUMBLE_PORT) {
url.setPort(usPort);
}

url.setUserName(qsUserName);

if (withPassword && !qsPassword.isEmpty()) {
url.setPassword(qsPassword);
}

return url;
}

@@ -146,6 +146,9 @@ class ServerHandler : public QThread {
void requestChannelPermissions(unsigned int channel);
void setSelfMuteDeafState(bool mute, bool deaf);
void announceRecordingState(bool recording);

/// Return connection information as a URL
QUrl getServerURL(bool withPassword = false) const;

void disconnect();
void run() Q_DECL_OVERRIDE;
@@ -128,6 +128,7 @@ int main(int argc, char **argv) {
#endif

bool bAllowMultiple = false;
bool suppressIdentity = false;
bool bRpcMode = false;
QString rpcCommand;
QUrl url;
@@ -193,6 +194,7 @@ int main(int argc, char **argv) {
} else if (args.at(i) == QLatin1String("-m") || args.at(i) == QLatin1String("--multiple")) {
bAllowMultiple = true;
} else if (args.at(i) == QLatin1String("-n") || args.at(i) == QLatin1String("--noidentity")) {
suppressIdentity = true;
g.s.bSuppressIdentity = true;
} else if (args.at(i) == QLatin1String("rpc")) {
bRpcMode = true;
@@ -508,10 +510,13 @@ int main(int argc, char **argv) {

g.s.save();

url.clear();

ServerHandlerPtr sh = g.sh;

if (sh && sh->isRunning())
if (sh && sh->isRunning()) {
url = sh->getServerURL();
Database::setShortcuts(g.sh->qbaDigest, g.s.qlShortcuts);
}

Audio::stop();

@@ -553,6 +558,32 @@ int main(int argc, char **argv) {
google::protobuf::ShutdownProtobufLibrary();
#endif
#endif

// At this point termination of our process is immenent. We can safely
// launch another version of Mumble. The reason we do an actual
// restart instead of re-creating our data structures is that making
// sure we won't leave state is quite tricky. Mumble has quite a
// few spots which might not consider seeing to basic initializations.
// Until we invest the time to verify this, rather be safe (and a bit slower)
// than sorry (and crash/bug out). Also take care to reconnect if possible.
if (res == MUMBLE_EXIT_CODE_RESTART) {
QStringList arguments;

if (bAllowMultiple) arguments << QLatin1String("--multiple");
if (suppressIdentity) arguments << QLatin1String("--noidentity");
if (!url.isEmpty()) arguments << url.toString();

qWarning() << "Triggering restart of Mumble with arguments: " << arguments;

if(!QProcess::startDetached(qApp->applicationFilePath(), arguments)) {
QMessageBox::warning(NULL,
QApplication::tr("Failed to restart mumble"),
QApplication::tr("Mumble failed to restart itself. Please restart it manually.")
);
return 1;
}
return 0;
}
return res;
}

0 comments on commit c431d37

Please sign in to comment.
You can’t perform that action at this time.