Skip to content

Commit

Permalink
System-wide single instance for all users, fix shadowsocks#451
Browse files Browse the repository at this point in the history
  • Loading branch information
librehat committed Jul 23, 2017
1 parent a6f81d9 commit 72b4875
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 42 deletions.
11 changes: 1 addition & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,11 @@ Features
- Use multiple profiles simultaneously
- `config.ini` is located under `~/.config/shadowsocks-qt5/` on \*nix platforms, or under the application's directory on Windows.

Note
----

If `ss-qt5` crashes and the **only one instance** mode is checked,
you may need to manually delete `/tmp/qipc_sharedmemory_ShadowsocksQt*`
and `/tmp/qipc_systemsem_ShadowsocksQt*`.
Otherwise, `ss-qt5` will complain that another instance is already running.
Run `ss-qt5` again is also expected to work.

LICENSE
-------

![](http://www.gnu.org/graphics/lgplv3-147x51.png)

Copyright © 2014-2016 Symeon Huang
Copyright © 2014-2017 Symeon Huang

This project is licensed under version 3 of the GNU Lesser General Public License.
2 changes: 1 addition & 1 deletion shadowsocks-qt5.pro
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ CONFIG += c++11

TARGET = ss-qt5
TEMPLATE = app
VERSION = 2.8.1
VERSION = 2.9.0
DEFINES += APP_VERSION=\\\"$$VERSION\\\"

include(src/ss-qt5.pri)
Expand Down
15 changes: 4 additions & 11 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#include <QLibraryInfo>
#include <QLocale>
#include <QMessageBox>
#include <QSharedMemory>
#include <QDebug>
#include <QDir>
#include <QCommandLineParser>
Expand All @@ -15,23 +14,17 @@ MainWindow *mainWindow = nullptr;

static void onSignalRecv(int sig)
{
#ifdef Q_OS_UNIX
if (sig == SIGUSR1) {
if (mainWindow) {
mainWindow->show();
}
if (sig == SIGINT || sig == SIGTERM) {
qApp->quit();
} else {
qWarning("Unhandled signal %d", sig);
}
#endif
if (sig == SIGINT || sig == SIGTERM) qApp->quit();
}

void setupApplication(QApplication &a)
{
signal(SIGINT, onSignalRecv);
signal(SIGTERM, onSignalRecv);
#ifdef Q_OS_UNIX
signal(SIGUSR1, onSignalRecv);
#endif

a.setApplicationName(QString("shadowsocks-qt5"));
a.setApplicationDisplayName(QString("Shadowsocks-Qt5"));
Expand Down
40 changes: 20 additions & 20 deletions src/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
MainWindow::MainWindow(ConfigHelper *confHelper, QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
configHelper(confHelper)
configHelper(confHelper),
instanceRunning(false)
{
Q_ASSERT(configHelper);

Expand Down Expand Up @@ -448,7 +449,7 @@ void MainWindow::onAbout()
QString text = QString("<h1>Shadowsocks-Qt5</h1><p><b>Version %1</b><br />"
"Using libQtShadowsocks %2<br />"
"Using Botan %3.%4.%5</p>"
"<p>Copyright © 2014-2016 Symeon Huang "
"<p>Copyright © 2014-2017 Symeon Huang "
"(<a href='https://twitter.com/librehat'>"
"@librehat</a>)</p>"
"<p>License: <a href='http://www.gnu.org/licenses/lgpl.html'>"
Expand Down Expand Up @@ -558,31 +559,28 @@ bool MainWindow::isInstanceRunning() const

void MainWindow::initSingleInstance()
{
instanceRunning = false;

QString username = qgetenv("USER");
if (username.isEmpty()) {
username = qgetenv("USERNAME");
}

QString serverName = QCoreApplication::applicationName() + "_" + username;
const QString serverName = QCoreApplication::applicationName();
QLocalSocket socket;
socket.connectToServer(serverName);
if (socket.waitForConnected(500)) {
instanceRunning = true;
if (configHelper->isOnlyOneInstance()) {
qWarning() << "A instance from the same user is already running";
qWarning() << "An instance of ss-qt5 is already running";
}
socket.write(serverName.toUtf8());
QByteArray username = qgetenv("USER");
if (username.isEmpty()) {
username = qgetenv("USERNAME");
}
socket.write(username);
socket.waitForBytesWritten();
return;
}

/* Cann't connect to server, indicating it's the first instance of the user */
/* Can't connect to server, indicating it's the first instance of the user */
instanceServer = new QLocalServer(this);
instanceServer->setSocketOptions(QLocalServer::UserAccessOption);
instanceServer->setSocketOptions(QLocalServer::WorldAccessOption);
connect(instanceServer, &QLocalServer::newConnection,
this,&MainWindow::onSingleInstanceConnect);
this, &MainWindow::onSingleInstanceConnect);
if (instanceServer->listen(serverName)) {
/* Remove server in case of crashes */
if (instanceServer->serverError() == QAbstractSocket::AddressInUseError &&
Expand All @@ -601,16 +599,18 @@ void MainWindow::onSingleInstanceConnect()
}

if (socket->waitForReadyRead(1000)) {
QString username = qgetenv("USER");
QByteArray username = qgetenv("USER");
if (username.isEmpty()) {
username = qgetenv("USERNAME");
}

QByteArray byteArray = socket->readAll();
QString magic(byteArray);
if (magic == QCoreApplication::applicationName() + "_" + username) {
QByteArray recvUsername = socket->readAll();
if (recvUsername == username) {
// Only show the window if it's the same user
show();
} else {
qWarning("Another user is trying to run another instance of ss-qt5");
}
}
delete socket;
socket->deleteLater();
}

0 comments on commit 72b4875

Please sign in to comment.