Sophie

Sophie

distrib > Mageia > 5 > i586 > media > core-release-src > by-pkgid > 5a34252e39e95980eda09b8e947f601a > files > 1

kwayland-5.1.2-3.mga5.src.rpm

commit e6c7e90f15c4bf62a9d0c1aa155c67b9648b4d14
Author: Martin Gräßlin <mgraesslin@kde.org>
Date:   Mon Nov 17 16:01:18 2014 +0100

    Adding a new ClientConnection class for wrapping wl_client
    
    The ClientConnection is managed by Display. Whenever one tries to
    get a ClientConnection for a wl_client* and it doesn't exist yet a
    new one will be created and a clientConnected signal will be emitted.
    Also there is a clientDisconnected signal.
    
    ClientConnection provides access to pid, uid and gid. The idea is
    to extend it to provide access to all the resources created for the
    client.

diff --git a/autotests/server/test_display.cpp b/autotests/server/test_display.cpp
index 2c257c1..34becff 100644
--- a/autotests/server/test_display.cpp
+++ b/autotests/server/test_display.cpp
@@ -21,7 +21,14 @@ License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 #include <QtTest/QtTest>
 // WaylandServer
 #include "../../src/server/display.h"
+#include "../../src/server/clientconnection.h"
 #include "../../src/server/output_interface.h"
+// Wayland
+#include <wayland-server.h>
+// system
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
 
 using namespace KWayland::Server;
 
@@ -32,6 +39,7 @@ private Q_SLOTS:
     void testSocketName();
     void testStartStop();
     void testAddRemoveOutput();
+    void testClientConnection();
 };
 
 void TestWaylandServerDisplay::testSocketName()
@@ -101,5 +109,61 @@ void TestWaylandServerDisplay::testAddRemoveOutput()
     QVERIFY(display.outputs().isEmpty());
 }
 
+void TestWaylandServerDisplay::testClientConnection()
+{
+    Display display;
+    display.setSocketName(QStringLiteral("kwin-wayland-server-display-test-client-connection"));
+    display.start();
+    QSignalSpy connectedSpy(&display, SIGNAL(clientConnected(KWayland::Server::ClientConnection*)));
+    QVERIFY(connectedSpy.isValid());
+    QSignalSpy disconnectedSpy(&display, SIGNAL(clientDisconnected(KWayland::Server::ClientConnection*)));
+    QVERIFY(disconnectedSpy.isValid());
+
+    int sv[2];
+    QVERIFY(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) >= 0);
+
+    auto client = wl_client_create(display, sv[0]);
+    QVERIFY(client);
+
+    QVERIFY(connectedSpy.isEmpty());
+    ClientConnection *connection = display.getConnection(client);
+    QVERIFY(connection);
+    QCOMPARE(connection->client(), client);
+    QVERIFY(connection->userId() != 0);
+    QVERIFY(connection->groupId() != 0);
+    QVERIFY(connection->processId() != 0);
+    QCOMPARE((wl_client*)*connection, client);
+    const ClientConnection &constRef = *connection;
+    QCOMPARE((wl_client*)constRef, client);
+    QCOMPARE(connectedSpy.count(), 1);
+    QCOMPARE(connectedSpy.first().first().value<ClientConnection*>(), connection);
+
+    QCOMPARE(connection, display.getConnection(client));
+    QCOMPARE(connectedSpy.count(), 1);
+
+    // create a second client
+    int sv2[2];
+    QVERIFY(socketpair(AF_UNIX, SOCK_STREAM, 0, sv2) >= 0);
+    auto client2 = wl_client_create(display, sv2[0]);
+    QVERIFY(client2);
+    ClientConnection *connection2 = display.getConnection(client2);
+    QVERIFY(connection2);
+    QCOMPARE(connection2->client(), client2);
+    QCOMPARE(connectedSpy.count(), 2);
+    QCOMPARE(connectedSpy.first().first().value<ClientConnection*>(), connection);
+    QCOMPARE(connectedSpy.last().first().value<ClientConnection*>(), connection2);
+
+    // and destroy
+    QVERIFY(disconnectedSpy.isEmpty());
+    wl_client_destroy(client);
+    QCOMPARE(disconnectedSpy.count(), 1);
+    wl_client_destroy(client2);
+    QCOMPARE(disconnectedSpy.count(), 2);
+    close(sv[0]);
+    close(sv[1]);
+    close(sv2[0]);
+    close(sv2[1]);
+}
+
 QTEST_GUILESS_MAIN(TestWaylandServerDisplay)
 #include "test_display.moc"
diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt
index e3f58cc..bd64770 100644
--- a/src/server/CMakeLists.txt
+++ b/src/server/CMakeLists.txt
@@ -1,5 +1,6 @@
 set(SERVER_LIB_SRCS
     buffer_interface.cpp
+    clientconnection.cpp
     compositor_interface.cpp
     display.cpp
     output_interface.cpp
@@ -50,6 +51,7 @@ set_target_properties(KF5WaylandServer PROPERTIES VERSION   ${KWAYLAND_VERSION_S
  install(FILES
    ${CMAKE_CURRENT_BINARY_DIR}/kwaylandserver_export.h
    buffer_interface.h
+   clientconnection.h
    compositor_interface.h
    display.h
    output_interface.h
diff --git a/src/server/clientconnection.cpp b/src/server/clientconnection.cpp
new file mode 100644
index 0000000..502db67
--- /dev/null
+++ b/src/server/clientconnection.cpp
@@ -0,0 +1,129 @@
+/********************************************************************
+Copyright 2014  Martin Gräßlin <mgraesslin@kde.org>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) version 3, or any
+later version accepted by the membership of KDE e.V. (or its
+successor approved by the membership of KDE e.V.), which shall
+act as a proxy defined in Section 6 of version 3 of the license.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+#include "clientconnection.h"
+#include "display.h"
+// Qt
+#include <QVector>
+// Wayland
+#include <wayland-server.h>
+
+namespace KWayland
+{
+namespace Server
+{
+
+class ClientConnection::Private
+{
+public:
+    explicit Private(wl_client *c, Display *display, ClientConnection *q);
+    ~Private();
+
+    wl_client *client;
+    Display *display;
+    pid_t pid = 0;
+    uid_t user = 0;
+    gid_t group = 0;
+
+private:
+    static void destroyListenerCallback(wl_listener *listener, void *data);
+    ClientConnection *q;
+    wl_listener listener;
+    static QVector<Private*> s_allClients;
+};
+
+QVector<ClientConnection::Private*> ClientConnection::Private::s_allClients;
+
+ClientConnection::Private::Private(wl_client *c, Display *display, ClientConnection *q)
+    : client(c)
+    , display(display)
+    , q(q)
+{
+    s_allClients << this;
+    listener.notify = destroyListenerCallback;
+    wl_client_add_destroy_listener(c, &listener);
+    wl_client_get_credentials(client, &pid, &user, &group);
+}
+
+ClientConnection::Private::~Private()
+{
+    wl_list_remove(&listener.link);
+    s_allClients.removeAt(s_allClients.indexOf(this));
+}
+
+void ClientConnection::Private::destroyListenerCallback(wl_listener *listener, void *data)
+{
+    Q_UNUSED(listener)
+    wl_client *client = reinterpret_cast<wl_client*>(data);
+    auto it = std::find_if(s_allClients.constBegin(), s_allClients.constEnd(),
+        [client](Private *c) {
+            return c->client == client;
+        }
+    );
+    Q_ASSERT(it != s_allClients.constEnd());
+    auto q = (*it)->q;
+    emit q->disconnected(q);
+    delete q;
+}
+
+ClientConnection::ClientConnection(wl_client *c, Display *parent)
+    : QObject(parent)
+    , d(new Private(c, parent, this))
+{
+}
+
+ClientConnection::~ClientConnection() = default;
+
+wl_client *ClientConnection::client()
+{
+    return d->client;
+}
+
+ClientConnection::operator wl_client*()
+{
+    return d->client;
+}
+
+ClientConnection::operator wl_client*() const
+{
+    return d->client;
+}
+
+Display *ClientConnection::display()
+{
+    return d->display;
+}
+
+gid_t ClientConnection::groupId() const
+{
+    return d->group;
+}
+
+pid_t ClientConnection::processId() const
+{
+    return d->pid;
+}
+
+uid_t ClientConnection::userId() const
+{
+    return d->user;
+}
+
+}
+}
diff --git a/src/server/clientconnection.h b/src/server/clientconnection.h
new file mode 100644
index 0000000..5a90eea
--- /dev/null
+++ b/src/server/clientconnection.h
@@ -0,0 +1,67 @@
+/********************************************************************
+Copyright 2014  Martin Gräßlin <mgraesslin@kde.org>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) version 3, or any
+later version accepted by the membership of KDE e.V. (or its
+successor approved by the membership of KDE e.V.), which shall
+act as a proxy defined in Section 6 of version 3 of the license.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+#ifndef KWAYLAND_SERVER_CLIENTCONNECTION_H
+#define KWAYLAND_SERVER_CLIENTCONNECTION_H
+
+#include <QObject>
+
+#include <kwaylandserver_export.h>
+
+struct wl_client;
+
+namespace KWayland
+{
+namespace Server
+{
+
+class Display;
+
+class KWAYLANDSERVER_EXPORT ClientConnection : public QObject
+{
+    Q_OBJECT
+public:
+    virtual ~ClientConnection();
+
+    wl_client *client();
+    Display *display();
+
+    pid_t processId() const;
+    uid_t userId() const;
+    gid_t groupId() const;
+
+    operator wl_client*();
+    operator wl_client*() const;
+
+Q_SIGNALS:
+    void disconnected(KWayland::Server::ClientConnection*);
+
+private:
+    friend class Display;
+    explicit ClientConnection(wl_client *c, Display *parent);
+    class Private;
+    QScopedPointer<Private> d;
+};
+
+}
+}
+
+Q_DECLARE_METATYPE(KWayland::Server::ClientConnection*)
+
+#endif
diff --git a/src/server/display.cpp b/src/server/display.cpp
index 350395f..25df978 100644
--- a/src/server/display.cpp
+++ b/src/server/display.cpp
@@ -50,6 +50,7 @@ public:
     QString socketName = QStringLiteral("wayland-0");
     bool running = false;
     QList<OutputInterface*> outputs;
+    QVector<ClientConnection*> clients;
 
 private:
     Display *q;
@@ -246,6 +247,32 @@ QList< OutputInterface* > Display::outputs() const
     return d->outputs;
 }
 
+ClientConnection *Display::getConnection(wl_client *client)
+{
+    Q_ASSERT(client);
+    auto it = std::find_if(d->clients.constBegin(), d->clients.constEnd(),
+        [client](ClientConnection *c) {
+            return c->client() == client;
+        }
+    );
+    if (it != d->clients.constEnd()) {
+        return *it;
+    }
+    // no ConnectionData yet, create it
+    auto c = new ClientConnection(client, this);
+    d->clients << c;
+    connect(c, &ClientConnection::disconnected, this,
+        [this] (ClientConnection *c) {
+            const int index = d->clients.indexOf(c);
+            Q_ASSERT(index != -1);
+            d->clients.remove(index);
+            Q_ASSERT(d->clients.indexOf(c) == -1);
+            emit clientDisconnected(c);
+        }
+    );
+    emit clientConnected(c);
+    return c;
+}
 
 }
 }
diff --git a/src/server/display.h b/src/server/display.h
index 36b8d5d..88d4f43 100644
--- a/src/server/display.h
+++ b/src/server/display.h
@@ -25,6 +25,9 @@ License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 
 #include <kwaylandserver_export.h>
 
+#include "clientconnection.h"
+
+struct wl_client;
 struct wl_display;
 struct wl_event_loop;
 
@@ -89,10 +92,20 @@ public:
     ShellInterface *createShell(QObject *parent = nullptr);
     SeatInterface *createSeat(QObject *parent = nullptr);
 
+    /**
+     * Gets the ClientConnection for the given @p client.
+     * If there is no ClientConnection yet for the given @p client, it will be created.
+     * @param client The native client for which the ClientConnection is retrieved
+     * @return The ClientConnection for the given native client
+     **/
+    ClientConnection *getConnection(wl_client *client);
+
 Q_SIGNALS:
     void socketNameChanged(const QString&);
     void runningChanged(bool);
     void aboutToTerminate();
+    void clientConnected(KWayland::Server::ClientConnection*);
+    void clientDisconnected(KWayland::Server::ClientConnection*);
 
 private:
     class Private;