summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Griebl <robert.griebl@qt.io>2022-03-01 17:41:36 +0100
committerRobert Griebl <robert.griebl@qt.io>2022-03-02 19:04:47 +0000
commit59d78be1056a3ba9db7f05bed71a7b7f48ee6405 (patch)
treefec70da4af647f13b7e644ada1e91102583f8dc0
parent3fe0a999d7a89141c7c03ca797fc7d65e07e9c52 (diff)
downloadqtapplicationmanager-59d78be1056a3ba9db7f05bed71a7b7f48ee6405.tar.gz
Create extra sockets only just before the Wayland compositor is created
Otherwise there will be a window where the socket already exists in file system, but is not adopted by the compositor yet, leading to "connection refused" errors should a client try to connect. Change-Id: Ic96c51c7e8175ab5e9ac40fc70b5f8dc97c11b71 Reviewed-by: Dominik Holland <dominik.holland@qt.io> (cherry picked from commit 9429d8e84649a4c0a262c16a2eaf394dcc90c79b)
-rw-r--r--src/main-lib/main.cpp116
-rw-r--r--src/window-lib/windowmanager.cpp3
-rw-r--r--src/window-lib/windowmanager.h16
3 files changed, 83 insertions, 52 deletions
diff --git a/src/main-lib/main.cpp b/src/main-lib/main.cpp
index d1d3d11e..03d56747 100644
--- a/src/main-lib/main.cpp
+++ b/src/main-lib/main.cpp
@@ -702,66 +702,82 @@ void Main::setupWindowManager(const QString &waylandSocketName, const QVariantLi
m_windowManager->enableWatchdog(!uiWatchdog);
#if defined(QT_WAYLANDCOMPOSITOR_LIB)
- for (const auto &v : waylandExtraSockets) {
- const QVariantMap &wes = v.toMap();
+ connect(&m_windowManager->internalSignals, &WindowManagerInternalSignals::compositorAboutToBeCreated,
+ this, [this, waylandExtraSockets] {
+ // This needs to be delayed until directly before creating the Wayland compositor.
+ // Otherwise we have a "dangling" socket you cannot connect to.
- const QString path = wes.value(qSL("path")).toString();
+ for (const auto &v : waylandExtraSockets) {
+ const QVariantMap &wes = v.toMap();
- if (path.isEmpty())
- continue;
- QFileInfo fi(path);
- if (!fi.dir().mkpath(qSL(".")))
- throw Exception("could not create path to extra Wayland socket: %1").arg(path);
+ const QString path = wes.value(qSL("path")).toString();
- auto sudo = SudoClient::instance();
+ if (path.isEmpty())
+ continue;
- if (!sudo || sudo->isFallbackImplementation())
- QLocalServer::removeServer(path); // if it fails, we'll notice in listen() right away
- else
- sudo->removeRecursive(path);
+ try {
+ QFileInfo fi(path);
+ if (!fi.dir().mkpath(qSL(".")))
+ throw Exception("could not create path to extra Wayland socket: %1").arg(path);
- QScopedPointer<QLocalServer> extraSocket(new QLocalServer);
- extraSocket->setMaxPendingConnections(0); // disable Qt's new connection handling
- if (!extraSocket->listen(path)) {
- throw Exception("could not listen on extra Wayland socket %1: %2")
- .arg(path, extraSocket->errorString());
- }
- int mode = wes.value(qSL("permissions"), -1).toInt();
- int uid = wes.value(qSL("userId"), -1).toInt();
- int gid = wes.value(qSL("groupId"), -1).toInt();
-
- QByteArray encodedPath = QFile::encodeName(path);
-
- if ((mode > 0) || (uid != -1) || (gid != -1)) {
- if (!sudo || sudo->isFallbackImplementation()) {
- if (mode > 0) {
- if (::chmod(encodedPath, static_cast<mode_t>(mode)) != 0)
- throw Exception(errno, "could not chmod(mode: %1) the extra Wayland socket %2")
- .arg(QString::number(mode, 8), path);
+ auto sudo = SudoClient::instance();
+
+ if (!sudo || sudo->isFallbackImplementation()) {
+ if (!QLocalServer::removeServer(path)) {
+ throw Exception("could not clean up leftover extra Wayland socket %1").arg(path);
+ }
+ } else {
+ sudo->removeRecursive(path);
}
- if ((uid != -1) || (gid != -1)) {
- if (::chown(encodedPath, static_cast<uid_t>(uid), static_cast<gid_t>(gid)) != 0)
- throw Exception(errno, "could not chown(uid: %1, gid: %2) the extra Wayland socket %3")
- .arg(uid).arg(gid).arg(path);
+
+ QScopedPointer<QLocalServer> extraSocket(new QLocalServer);
+ extraSocket->setMaxPendingConnections(0); // disable Qt's new connection handling
+ if (!extraSocket->listen(path)) {
+ throw Exception("could not listen on extra Wayland socket %1: %2")
+ .arg(path, extraSocket->errorString());
}
- } else {
- if (!sudo->setOwnerAndPermissionsRecursive(path, static_cast<uid_t>(uid),
- static_cast<gid_t>(gid),
- static_cast<mode_t>(mode))) {
- throw Exception(Error::IO, "could not change the owner to %1:%2 and the permission"
- " bits to %3 for the extra Wayland socket %4: %5")
- .arg(uid).arg(gid).arg(mode, 0, 8).arg(path).arg(sudo->lastError());
+ int mode = wes.value(qSL("permissions"), -1).toInt();
+ int uid = wes.value(qSL("userId"), -1).toInt();
+ int gid = wes.value(qSL("groupId"), -1).toInt();
+
+ QByteArray encodedPath = QFile::encodeName(path);
+
+ if ((mode > 0) || (uid != -1) || (gid != -1)) {
+ if (!sudo || sudo->isFallbackImplementation()) {
+ if (mode > 0) {
+ if (::chmod(encodedPath, static_cast<mode_t>(mode)) != 0)
+ throw Exception(errno, "could not chmod(mode: %1) the extra Wayland socket %2")
+ .arg(QString::number(mode, 8), path);
+ }
+ if ((uid != -1) || (gid != -1)) {
+ if (::chown(encodedPath, static_cast<uid_t>(uid), static_cast<gid_t>(gid)) != 0)
+ throw Exception(errno, "could not chown(uid: %1, gid: %2) the extra Wayland socket %3")
+ .arg(uid).arg(gid).arg(path);
+ }
+ } else {
+ if (!sudo->setOwnerAndPermissionsRecursive(path, static_cast<uid_t>(uid),
+ static_cast<gid_t>(gid),
+ static_cast<mode_t>(mode))) {
+ throw Exception(Error::IO, "could not change the owner to %1:%2 and the permission"
+ " bits to %3 for the extra Wayland socket %4: %5")
+ .arg(uid).arg(gid).arg(mode, 0, 8).arg(path).arg(sudo->lastError());
+ }
+ // if we changed the owner, ~QLocalServer might not be able to clean up the
+ // socket inode, so we need to sudo this removal as well
+ QObject::connect(extraSocket.data(), &QObject::destroyed, [path, sudo]() {
+ sudo->removeRecursive(path);
+ });
+ }
}
- // if we changed the owner, ~QLocalServer might not be able to clean up the
- // socket inode, so we need to sudo this removal as well
- QObject::connect(extraSocket.data(), &QObject::destroyed, [path, sudo]() {
- sudo->removeRecursive(path);
- });
+
+ m_windowManager->addWaylandSocket(extraSocket.take());
+ } catch (const std::exception &e) {
+ qCCritical(LogSystem) << "ERROR:" << e.what();
}
}
-
- m_windowManager->addWaylandSocket(extraSocket.take());
- }
+ });
+#else
+ Q_UNUSED(waylandExtraSockets)
#endif
QObject::connect(&m_applicationManager->internalSignals, &ApplicationManagerInternalSignals::newRuntimeCreated,
diff --git a/src/window-lib/windowmanager.cpp b/src/window-lib/windowmanager.cpp
index 69201f01..d237f295 100644
--- a/src/window-lib/windowmanager.cpp
+++ b/src/window-lib/windowmanager.cpp
@@ -687,6 +687,9 @@ void WindowManager::registerCompositorView(QQuickWindow *view)
#if defined(AM_MULTI_PROCESS)
if (!ApplicationManager::instance()->isSingleProcess()) {
if (!d->waylandCompositor) {
+ // this will trigger the creation of extra sockets in main.cpp
+ emit internalSignals.compositorAboutToBeCreated();
+
d->waylandCompositor = new WaylandCompositor(view, d->waylandSocketName);
for (const auto &extraSocket : d->extraWaylandSockets)
d->waylandCompositor->addSocketDescriptor(extraSocket);
diff --git a/src/window-lib/windowmanager.h b/src/window-lib/windowmanager.h
index 466275fd..8b7fc3dc 100644
--- a/src/window-lib/windowmanager.h
+++ b/src/window-lib/windowmanager.h
@@ -68,6 +68,17 @@ class Application;
class AbstractRuntime;
class WaylandCompositor;
+
+// A place to collect signals used internally by appman without polluting
+// WindowManager's public QML API.
+class WindowManagerInternalSignals : public QObject
+{
+ Q_OBJECT
+signals:
+ // Emitted right before the WaylandCompositor instance is created
+ void compositorAboutToBeCreated();
+};
+
class WindowManager : public QAbstractListModel
{
Q_OBJECT
@@ -106,6 +117,9 @@ public:
Q_INVOKABLE int indexOfWindow(Window *window) const;
Q_INVOKABLE QObject *addExtension(QQmlComponent *component) const;
+ WindowManagerInternalSignals internalSignals;
+
+protected:
bool eventFilter(QObject *watched, QEvent *event) override;
signals:
@@ -124,8 +138,6 @@ signals:
void slowAnimationsChanged(bool);
- void _inProcessSurfaceItemReleased(QSharedPointer<InProcessSurfaceItem>);
-
private slots:
void inProcessSurfaceItemCreated(QSharedPointer<InProcessSurfaceItem> surfaceItem);
void setupWindow(QT_PREPEND_NAMESPACE_AM(Window) *window);