Navigation Menu

Skip to content

Commit

Permalink
Add self-restart capability to client
Browse files Browse the repository at this point in the history
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 13, 2015
1 parent 7fbe61e commit c431d37
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 2 deletions.
3 changes: 3 additions & 0 deletions src/mumble/Global.h
Expand Up @@ -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.
Expand Down
19 changes: 19 additions & 0 deletions src/mumble/ServerHandler.cpp
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

3 changes: 3 additions & 0 deletions src/mumble/ServerHandler.h
Expand Up @@ -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;
Expand Down
35 changes: 33 additions & 2 deletions src/mumble/main.cpp
Expand Up @@ -128,6 +128,7 @@ int main(int argc, char **argv) {
#endif

bool bAllowMultiple = false;
bool suppressIdentity = false;
bool bRpcMode = false;
QString rpcCommand;
QUrl url;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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;
}

Expand Down

0 comments on commit c431d37

Please sign in to comment.