1 /*
2     SPDX-FileCopyrightText: 2016 Oleg Chernovskiy <kanedias@xaker.ru>
3 
4     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5 */
6 #include "remote_access_interface.h"
7 #include "display.h"
8 #include "global_p.h"
9 #include "logging.h"
10 #include "output_interface.h"
11 #include "remote_access_interface_p.h"
12 #include "resource_p.h"
13 
14 #include <wayland-remote-access-server-protocol.h>
15 
16 #include <QHash>
17 #include <QMutableHashIterator>
18 
19 #include <functional>
20 
21 namespace KWayland
22 {
23 namespace Server
24 {
25 class BufferHandle::Private // @see gbm_import_fd_data
26 {
27 public:
28     // Note that on client side received fd number will be different
29     // and meaningful only for client process!
30     // Thus we can use server-side fd as an implicit unique id
31     qint32 fd = 0; ///< also internal buffer id for client
32     quint32 width = 0;
33     quint32 height = 0;
34     quint32 stride = 0;
35     quint32 format = 0;
36 };
37 
BufferHandle()38 BufferHandle::BufferHandle()
39     : d(new Private)
40 {
41 }
42 
~BufferHandle()43 BufferHandle::~BufferHandle()
44 {
45 }
46 
setFd(qint32 fd)47 void BufferHandle::setFd(qint32 fd)
48 {
49     d->fd = fd;
50 }
51 
fd() const52 qint32 BufferHandle::fd() const
53 {
54     return d->fd;
55 }
56 
setSize(quint32 width,quint32 height)57 void BufferHandle::setSize(quint32 width, quint32 height)
58 {
59     d->width = width;
60     d->height = height;
61 }
62 
width() const63 quint32 BufferHandle::width() const
64 {
65     return d->width;
66 }
67 
height() const68 quint32 BufferHandle::height() const
69 {
70     return d->height;
71 }
72 
setStride(quint32 stride)73 void BufferHandle::setStride(quint32 stride)
74 {
75     d->stride = stride;
76 }
77 
stride() const78 quint32 BufferHandle::stride() const
79 {
80     return d->stride;
81 }
82 
setFormat(quint32 format)83 void BufferHandle::setFormat(quint32 format)
84 {
85     d->format = format;
86 }
87 
format() const88 quint32 BufferHandle::format() const
89 {
90     return d->format;
91 }
92 
93 /**
94  * @brief helper struct for manual reference counting.
95  * automatic counting via QSharedPointer is no-go here as we hold strong reference in sentBuffers.
96  */
97 struct BufferHolder {
98     const BufferHandle *buf;
99     quint64 counter;
100 };
101 
102 class RemoteAccessManagerInterface::Private : public Global::Private
103 {
104 public:
105     Private(RemoteAccessManagerInterface *q, Display *d);
106     ~Private() override;
107 
108     /**
109      * @brief Send buffer ready notification to all connected clients
110      * @param output wl_output interface to determine which screen sent this buf
111      * @param buf buffer containing GBM-related params
112      */
113     void sendBufferReady(const OutputInterface *output, const BufferHandle *buf);
114     /**
115      * @brief Release all bound buffers associated with this resource
116      * @param resource one of bound clients
117      */
118     void release(wl_resource *resource);
119 
120     /**
121      * Clients of this interface.
122      * This may be screenshot app, video capture app,
123      * remote control app etc.
124      */
125     QList<wl_resource *> clientResources;
126 
127 private:
128     // methods
129     static void unbind(wl_resource *resource);
cast(wl_resource * r)130     static Private *cast(wl_resource *r)
131     {
132         return reinterpret_cast<Private *>(wl_resource_get_user_data(r));
133     }
134     static void getBufferCallback(wl_client *client, wl_resource *resource, uint32_t buffer, int32_t internalBufId);
135     static void releaseCallback(wl_client *client, wl_resource *resource);
136     void bind(wl_client *client, uint32_t version, uint32_t id) override;
137 
138     /**
139      * @brief Unreferences counter and frees buffer when it reaches zero
140      * @param buf holder to decrease reference counter on
141      * @return true if buffer was released, false otherwise
142      */
143     bool unref(BufferHolder &buf);
144 
145     // fields
146     static const struct org_kde_kwin_remote_access_manager_interface s_interface;
147     static const quint32 s_version;
148 
149     RemoteAccessManagerInterface *q;
150 
151     /**
152      * Buffers that were sent but still not acked by server
153      * Keys are fd numbers as they are unique
154      **/
155     QHash<qint32, BufferHolder> sentBuffers;
156 };
157 
158 const quint32 RemoteAccessManagerInterface::Private::s_version = 1;
159 
Private(RemoteAccessManagerInterface * q,Display * d)160 RemoteAccessManagerInterface::Private::Private(RemoteAccessManagerInterface *q, Display *d)
161     : Global::Private(d, &org_kde_kwin_remote_access_manager_interface, s_version)
162     , q(q)
163 {
164 }
165 
bind(wl_client * client,uint32_t version,uint32_t id)166 void RemoteAccessManagerInterface::Private::bind(wl_client *client, uint32_t version, uint32_t id)
167 {
168     // create new client resource
169     auto c = display->getConnection(client);
170     wl_resource *resource = c->createResource(&org_kde_kwin_remote_access_manager_interface, qMin(version, s_version), id);
171     if (!resource) {
172         wl_client_post_no_memory(client);
173         return;
174     }
175     wl_resource_set_implementation(resource, &s_interface, this, unbind);
176 
177     // add newly created client resource to the list
178     clientResources << resource;
179 }
180 
sendBufferReady(const OutputInterface * output,const BufferHandle * buf)181 void RemoteAccessManagerInterface::Private::sendBufferReady(const OutputInterface *output, const BufferHandle *buf)
182 {
183     BufferHolder holder{buf, 0};
184     // notify clients
185     qCDebug(KWAYLAND_SERVER) << "Server buffer sent: fd" << buf->fd();
186     for (auto res : clientResources) {
187         auto client = wl_resource_get_client(res);
188         auto boundScreens = output->clientResources(display->getConnection(client));
189 
190         // clients don't necessarily bind outputs
191         if (boundScreens.isEmpty()) {
192             continue;
193         }
194 
195         // no reason for client to bind wl_output multiple times, send only to first one
196         org_kde_kwin_remote_access_manager_send_buffer_ready(res, buf->fd(), boundScreens[0]);
197         holder.counter++;
198     }
199     if (holder.counter == 0) {
200         // buffer was not requested by any client
201         Q_EMIT q->bufferReleased(buf);
202         return;
203     }
204     // store buffer locally, clients will ask it later
205     sentBuffers[buf->fd()] = holder;
206 }
207 
208 #ifndef K_DOXYGEN
209 const struct org_kde_kwin_remote_access_manager_interface RemoteAccessManagerInterface::Private::s_interface = {getBufferCallback, releaseCallback};
210 #endif
211 
getBufferCallback(wl_client * client,wl_resource * resource,uint32_t buffer,int32_t internalBufId)212 void RemoteAccessManagerInterface::Private::getBufferCallback(wl_client *client, wl_resource *resource, uint32_t buffer, int32_t internalBufId)
213 {
214     Private *p = cast(resource);
215 
216     // client asks for buffer we earlier announced, we must have it
217     if (Q_UNLIKELY(!p->sentBuffers.contains(internalBufId))) { // no such buffer (?)
218         wl_resource_post_no_memory(resource);
219         return;
220     }
221 
222     BufferHolder &bh = p->sentBuffers[internalBufId];
223     auto rbuf = new RemoteBufferInterface(p->q, resource, bh.buf);
224     rbuf->create(p->display->getConnection(client), wl_resource_get_version(resource), buffer);
225     if (!rbuf->resource()) {
226         wl_resource_post_no_memory(resource);
227         delete rbuf;
228         return;
229     }
230 
231     QObject::connect(rbuf, &Resource::aboutToBeUnbound, p->q, [p, rbuf, resource, &bh] {
232         if (!p->clientResources.contains(resource)) {
233             // remote buffer destroy confirmed after client is already gone
234             // all relevant buffers are already unreferenced
235             return;
236         }
237         qCDebug(KWAYLAND_SERVER) << "Remote buffer returned, client" << wl_resource_get_id(resource) << ", id" << rbuf->id() << ", fd" << bh.buf->fd();
238         if (p->unref(bh)) {
239             p->sentBuffers.remove(bh.buf->fd());
240         }
241     });
242 
243     // send buffer params
244     rbuf->passFd();
245 }
246 
releaseCallback(wl_client * client,wl_resource * resource)247 void RemoteAccessManagerInterface::Private::releaseCallback(wl_client *client, wl_resource *resource)
248 {
249     Q_UNUSED(client);
250     unbind(resource);
251 }
252 
unref(BufferHolder & bh)253 bool RemoteAccessManagerInterface::Private::unref(BufferHolder &bh)
254 {
255     bh.counter--;
256     if (!bh.counter) {
257         // no more clients using this buffer
258         qCDebug(KWAYLAND_SERVER) << "Buffer released, fd" << bh.buf->fd();
259         Q_EMIT q->bufferReleased(bh.buf);
260         return true;
261     }
262 
263     return false;
264 }
265 
unbind(wl_resource * resource)266 void RemoteAccessManagerInterface::Private::unbind(wl_resource *resource)
267 {
268     // we're unbinding, all sent buffers for this client are now effectively invalid
269     Private *p = cast(resource);
270     p->release(resource);
271 }
272 
release(wl_resource * resource)273 void RemoteAccessManagerInterface::Private::release(wl_resource *resource)
274 {
275     // all holders should decrement their counter as one client is gone
276     QMutableHashIterator<qint32, BufferHolder> itr(sentBuffers);
277     while (itr.hasNext()) {
278         BufferHolder &bh = itr.next().value();
279         if (unref(bh)) {
280             itr.remove();
281         }
282     }
283 
284     clientResources.removeAll(resource);
285 }
286 
~Private()287 RemoteAccessManagerInterface::Private::~Private()
288 {
289     // server deletes created interfaces, release all held buffers
290     auto c = clientResources; // shadow copy
291     for (auto res : c) {
292         release(res);
293     }
294 }
295 
RemoteAccessManagerInterface(Display * display,QObject * parent)296 RemoteAccessManagerInterface::RemoteAccessManagerInterface(Display *display, QObject *parent)
297     : Global(new Private(this, display), parent)
298 {
299 }
300 
sendBufferReady(const OutputInterface * output,const BufferHandle * buf)301 void RemoteAccessManagerInterface::sendBufferReady(const OutputInterface *output, const BufferHandle *buf)
302 {
303     Private *priv = reinterpret_cast<Private *>(d.data());
304     priv->sendBufferReady(output, buf);
305 }
306 
isBound() const307 bool RemoteAccessManagerInterface::isBound() const
308 {
309     Private *priv = reinterpret_cast<Private *>(d.data());
310     return !priv->clientResources.isEmpty();
311 }
312 
313 class RemoteBufferInterface::Private : public Resource::Private
314 {
315 public:
316     Private(RemoteAccessManagerInterface *ram, RemoteBufferInterface *q, wl_resource *pResource, const BufferHandle *buf);
317     ~Private() override;
318 
319     void passFd();
320 
321 private:
322     static const struct org_kde_kwin_remote_buffer_interface s_interface;
323 
324     const BufferHandle *wrapped;
325 };
326 
327 #ifndef K_DOXYGEN
328 const struct org_kde_kwin_remote_buffer_interface RemoteBufferInterface::Private::s_interface = {resourceDestroyedCallback};
329 #endif
330 
Private(RemoteAccessManagerInterface * ram,RemoteBufferInterface * q,wl_resource * pResource,const BufferHandle * buf)331 RemoteBufferInterface::Private::Private(RemoteAccessManagerInterface *ram, RemoteBufferInterface *q, wl_resource *pResource, const BufferHandle *buf)
332     : Resource::Private(q, ram, pResource, &org_kde_kwin_remote_buffer_interface, &s_interface)
333     , wrapped(buf)
334 {
335 }
336 
~Private()337 RemoteBufferInterface::Private::~Private()
338 {
339 }
340 
passFd()341 void RemoteBufferInterface::Private::passFd()
342 {
343     org_kde_kwin_remote_buffer_send_gbm_handle(resource, wrapped->fd(), wrapped->width(), wrapped->height(), wrapped->stride(), wrapped->format());
344 }
345 
RemoteBufferInterface(RemoteAccessManagerInterface * ram,wl_resource * pResource,const BufferHandle * buf)346 RemoteBufferInterface::RemoteBufferInterface(RemoteAccessManagerInterface *ram, wl_resource *pResource, const BufferHandle *buf)
347     : Resource(new Private(ram, this, pResource, buf), ram)
348 {
349 }
350 
d_func() const351 RemoteBufferInterface::Private *RemoteBufferInterface::d_func() const
352 {
353     return reinterpret_cast<Private *>(d.data());
354 }
355 
passFd()356 void RemoteBufferInterface::passFd()
357 {
358     d_func()->passFd();
359 }
360 
361 }
362 }
363