VirtualBox

source: vbox/trunk/src/VBox/Additions/x11/VBoxClient/wayland-helper-ipc.cpp@ 101878

Last change on this file since 101878 was 101878, checked in by vboxsync, 6 months ago

Additions: X11/Wayland: Add initial support for clipboard sharing with Gnome and Plasma Wayland guests (not yet enabled), bugref:10194.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 13.4 KB
Line 
1/* $Id: wayland-helper-ipc.cpp 101878 2023-11-06 15:36:24Z vboxsync $ */
2/** @file
3 * Guest Additions - IPC between VBoxClient and vboxwl tool.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#include <sys/types.h>
29#include <pwd.h>
30#include <unistd.h>
31
32#include <iprt/cdefs.h>
33#include <iprt/err.h>
34#include <iprt/linux/sysfs.h>
35#include <iprt/localipc.h>
36#include <iprt/mem.h>
37#include <iprt/crc.h>
38#include <iprt/env.h>
39#include <iprt/process.h>
40#include <iprt/asm.h>
41
42#include <VBox/GuestHost/clipboard-helper.h>
43
44#include "VBoxClient.h"
45#include "wayland-helper-ipc.h"
46
47RTDECL(int) vbcl_wayland_hlp_gtk_ipc_srv_name(char *szBuf, size_t cbBuf)
48{
49 int rc;
50
51 char pszActiveTTY[128];
52 size_t cchRead;
53 struct passwd *pwd;
54
55 AssertReturn(RT_VALID_PTR(szBuf), VERR_INVALID_PARAMETER);
56 AssertReturn(cbBuf > 0, VERR_INVALID_PARAMETER);
57
58 RT_BZERO(szBuf, cbBuf);
59 RT_ZERO(pszActiveTTY);
60
61 rc = RTStrCat(szBuf, cbBuf, "GtkHlpIpcServer-");
62 if (RT_SUCCESS(rc))
63 rc = RTLinuxSysFsReadStrFile(pszActiveTTY, sizeof(pszActiveTTY) - 1 /* reserve last byte for string termination */,
64 &cchRead, "class/tty/tty0/active");
65 if (RT_SUCCESS(rc))
66 rc = RTStrCat(szBuf, cbBuf, pszActiveTTY);
67
68 if (RT_SUCCESS(rc))
69 rc = RTStrCat(szBuf, cbBuf, "-");
70
71 pwd = getpwuid(geteuid());
72 if (RT_VALID_PTR(pwd))
73 {
74 if (RT_VALID_PTR(pwd->pw_name))
75 rc = RTStrCat(szBuf, cbBuf, pwd->pw_name);
76 else
77 rc = VERR_NOT_FOUND;
78 }
79 else
80 rc = VERR_NOT_FOUND;
81
82 return rc;
83}
84
85void vbcl::ipc::packet_dump(vbcl::ipc::packet_t *pPacket)
86{
87 VBClLogVerbose(3, "IPC packet dump:\n");
88 VBClLogVerbose(3, "u64Crc : 0x%x\n", pPacket->u64Crc);
89 VBClLogVerbose(3, "uSessionId: %u\n", pPacket->uSessionId);
90 VBClLogVerbose(3, "idCmd : %u\n", pPacket->idCmd);
91 VBClLogVerbose(3, "cbData: : %u\n", pPacket->cbData);
92}
93
94bool vbcl::ipc::packet_verify(vbcl::ipc::packet_t *pPacket, size_t cbPacket)
95{
96 bool fResult = false;
97
98 AssertPtrReturn(pPacket, VERR_INVALID_PARAMETER);
99 AssertReturn(cbPacket > sizeof(vbcl::ipc::packet_t), VERR_INVALID_PARAMETER);
100
101 AssertReturn( pPacket->idCmd > vbcl::ipc::CMD_UNKNOWN
102 && pPacket->idCmd < vbcl::ipc::CMD_MAX, VERR_INVALID_PARAMETER);
103
104 /* Exact size match. */
105 if (pPacket->cbData == cbPacket)
106 {
107 /* CRC check. */
108 uint64_t u64Crc = pPacket->u64Crc;
109 pPacket->u64Crc = 0;
110 if (u64Crc != 0 && RTCrc64(pPacket, pPacket->cbData) == u64Crc)
111 {
112 /* Verify payload size. */
113 size_t cbPayload = 0;
114
115 switch (pPacket->idCmd)
116 {
117 case vbcl::ipc::CLIP_FORMATS:
118 case vbcl::ipc::CLIP_FORMAT:
119 cbPayload = sizeof(vbcl::ipc::clipboard::formats_packet_t);
120 break;
121
122 case vbcl::ipc::CLIP_DATA:
123 {
124 vbcl::ipc::clipboard::data_packet_t *pDataEx = (vbcl::ipc::clipboard::data_packet_t *)pPacket;
125 cbPayload = sizeof(vbcl::ipc::clipboard::data_packet_t) + pDataEx->cbData;
126 break;
127 }
128
129 default:
130 break;
131 }
132
133 if (pPacket->cbData == cbPayload)
134 fResult = true;
135 else
136 VBClLogVerbose(3, "bad cmd size (%u vs %u)\n", pPacket->cbData, cbPayload);
137 }
138 else
139 VBClLogVerbose(3, "bad crc\n");
140
141 /* Restore CRC. */
142 pPacket->u64Crc = u64Crc;
143 }
144 else
145 VBClLogVerbose(3, "bad size\n");
146
147 return fResult;
148}
149
150int vbcl::ipc::packet_read(uint32_t uSessionId, RTLOCALIPCSESSION hSession, void **ppvData)
151{
152 int rc;
153
154 vbcl::ipc::packet_t Packet;
155 size_t cbRead;
156
157 AssertPtrReturn(ppvData, VERR_INVALID_PARAMETER);
158
159 rc = RTLocalIpcSessionWaitForData(hSession, VBOX_GTKIPC_RX_TIMEOUT_MS);
160 if (RT_SUCCESS(rc))
161 {
162 /* Read IPC message header. */
163 rc = RTLocalIpcSessionRead(hSession, &Packet, sizeof(Packet), &cbRead);
164 if (RT_SUCCESS(rc))
165 {
166 if (cbRead == sizeof(Packet))
167 {
168 bool fCheck = true;
169
170#define _CHECK(_cond, _msg, _ptr) \
171 if (fCheck) \
172 { \
173 fCheck &= _cond; \
174 if (!fCheck) \
175 VBClLogVerbose(3, _msg "\n", _ptr); \
176 }
177
178 _CHECK(Packet.u64Crc > 0, "bad crc: 0x%x", Packet.u64Crc);
179 _CHECK(Packet.uSessionId == uSessionId, "bad session id: %u vs %u", (Packet.uSessionId, uSessionId));
180 _CHECK(Packet.cbData > sizeof(Packet), "bad cbData: %u", Packet.cbData);
181
182 /* Receive the rest of a message. */
183 if (fCheck)
184 {
185 uint8_t *puData;
186
187 puData = (uint8_t *)RTMemAllocZ(Packet.cbData);
188 if (RT_VALID_PTR(puData))
189 {
190 /* Add generic header to the beginning of the output buffer
191 * and receive the rest of the data into it. */
192 memcpy(puData, &Packet, sizeof(Packet));
193
194 rc = RTLocalIpcSessionRead(hSession, puData + sizeof(Packet),
195 Packet.cbData - sizeof(Packet), &cbRead);
196 if (RT_SUCCESS(rc))
197 {
198 if (cbRead == (Packet.cbData - sizeof(Packet)))
199 {
200 if (vbcl::ipc::packet_verify((vbcl::ipc::packet_t *)puData, Packet.cbData))
201 {
202 /* Now return received data to the caller. */
203 *ppvData = puData;
204 }
205 else
206 rc = VERR_NOT_EQUAL;
207 }
208 else
209 rc = VERR_BUFFER_UNDERFLOW;
210 }
211
212 if (RT_FAILURE(rc))
213 RTMemFree(puData);
214 }
215 else
216 rc = VERR_NO_MEMORY;
217 }
218 else
219 rc = VERR_INVALID_PARAMETER;
220 }
221
222 if (RT_FAILURE(rc))
223 vbcl::ipc::packet_dump(&Packet);
224 }
225 }
226
227 return rc;
228}
229
230int vbcl::ipc::packet_write(RTLOCALIPCSESSION hSession, vbcl::ipc::packet_t *pPacket)
231{
232 int rc;
233
234 AssertPtrReturn(pPacket, VERR_INVALID_PARAMETER);
235
236 pPacket->u64Crc = 0;
237 pPacket->u64Crc = RTCrc64(pPacket, pPacket->cbData);
238
239 Assert(pPacket->u64Crc);
240
241 if (vbcl::ipc::packet_verify(pPacket, pPacket->cbData))
242 {
243 rc = RTLocalIpcSessionWrite(hSession, (void *)pPacket, pPacket->cbData);
244 if (RT_SUCCESS(rc))
245 rc = RTLocalIpcSessionFlush(hSession);
246 }
247 else
248 {
249 vbcl::ipc::packet_dump(pPacket);
250 rc = VERR_NOT_EQUAL;
251 }
252
253 return rc;
254}
255
256int vbcl::ipc::clipboard::ClipboardIpc::send_formats(uint32_t uSessionId, RTLOCALIPCSESSION hIpcSession)
257{
258 vbcl::ipc::clipboard::formats_packet_t Packet;
259 SHCLFORMATS fFormats;
260 int rc = VINF_SUCCESS;
261
262 RT_ZERO(Packet);
263
264 Packet.Hdr.u64Crc = 0;
265 Packet.Hdr.uSessionId = uSessionId;
266 Packet.Hdr.idCmd = CLIP_FORMATS;
267 Packet.Hdr.cbData = sizeof(Packet);
268
269 fFormats = m_fFmts.wait();
270 if (fFormats != m_fFmts.defaults())
271 {
272 Packet.fFormats = fFormats;
273 rc = vbcl::ipc::packet_write(hIpcSession, &Packet.Hdr);
274 }
275 else
276 rc = VERR_TIMEOUT;
277
278 VBClLogVerbose(3, "%s: send_formats [sid=%u, fmts=0x%x], rc=%Rrc\n",
279 m_fServer ? "server" : "client", uSessionId, fFormats, rc);
280
281 return rc;
282}
283
284int vbcl::ipc::clipboard::ClipboardIpc::recv_formats(uint32_t uSessionId, RTLOCALIPCSESSION hIpcSession)
285{
286 int rc;
287 vbcl::ipc::clipboard::formats_packet_t *pPacket;
288 vbcl::ipc::command_t idCmd = CMD_UNKNOWN;
289 SHCLFORMATS fFormats = VBOX_SHCL_FMT_NONE;
290
291 rc = vbcl::ipc::packet_read(uSessionId, hIpcSession, (void **)&pPacket);
292 if (RT_SUCCESS(rc))
293 {
294 if ( pPacket->Hdr.idCmd == CLIP_FORMATS
295 && vbcl::ipc::packet_verify(&pPacket->Hdr, pPacket->Hdr.cbData))
296 {
297 fFormats = pPacket->fFormats;
298 idCmd = pPacket->Hdr.idCmd;
299 m_fFmts.set(fFormats);
300 }
301 else
302 rc = VERR_WRONG_ORDER;
303
304 RTMemFree(pPacket);
305 }
306
307 VBClLogVerbose(3, "%s: recv_formats [sid=%u, cmd=0x%x, fmts=0x%x], rc=%Rrc\n",
308 m_fServer ? "server" : "client", uSessionId, idCmd, fFormats, rc);
309
310 return rc;
311}
312
313int vbcl::ipc::clipboard::ClipboardIpc::send_format(uint32_t uSessionId, RTLOCALIPCSESSION hIpcSession)
314{
315 vbcl::ipc::clipboard::formats_packet_t Packet;
316 SHCLFORMAT uFormat;
317 int rc = VINF_SUCCESS;
318
319 RT_ZERO(Packet);
320
321 Packet.Hdr.u64Crc = 0;
322 Packet.Hdr.uSessionId = uSessionId;
323 Packet.Hdr.idCmd = CLIP_FORMAT;
324 Packet.Hdr.cbData = sizeof(Packet);
325
326 uFormat = m_uFmt.wait();
327 if (uFormat != m_uFmt.defaults())
328 {
329 Packet.fFormats = uFormat;
330 rc = vbcl::ipc::packet_write(hIpcSession, &Packet.Hdr);
331 }
332 else
333 rc = VERR_TIMEOUT;
334
335 VBClLogVerbose(3, "%s: send_format [sid=%u, fmt=0x%x], rc=%Rrc\n",
336 m_fServer ? "server" : "client", uSessionId, uFormat, rc);
337
338 return rc;
339}
340
341int vbcl::ipc::clipboard::ClipboardIpc::recv_format(uint32_t uSessionId, RTLOCALIPCSESSION hIpcSession)
342{
343 int rc;
344 vbcl::ipc::clipboard::formats_packet_t *pPacket;
345 vbcl::ipc::command_t idCmd = CMD_UNKNOWN;
346 SHCLFORMATS uFormat = VBOX_SHCL_FMT_NONE;
347
348 rc = vbcl::ipc::packet_read(uSessionId, hIpcSession, (void **)&pPacket);
349 if (RT_SUCCESS(rc))
350 {
351 if ( pPacket->Hdr.idCmd == CLIP_FORMAT
352 && vbcl::ipc::packet_verify(&pPacket->Hdr, pPacket->Hdr.cbData))
353 {
354 uFormat = pPacket->fFormats;
355 idCmd = pPacket->Hdr.idCmd;
356 m_uFmt.set(uFormat);
357 }
358 else
359 rc = VERR_WRONG_ORDER;
360
361 RTMemFree(pPacket);
362 }
363
364 VBClLogVerbose(3, "%s: recv_format [sid=%u, cmd=0x%x, fmts=0x%x], rc=%Rrc\n",
365 m_fServer ? "server" : "client", uSessionId, idCmd, uFormat, rc);
366
367 return rc;
368}
369
370int vbcl::ipc::clipboard::ClipboardIpc::send_data(uint32_t uSessionId, RTLOCALIPCSESSION hIpcSession)
371{
372 vbcl::ipc::clipboard::data_packet_t *pPacket;
373 int rc = VINF_SUCCESS;
374
375 void *pvData;
376 uint32_t cbData;
377
378 cbData = m_cbClipboardBuf.wait();
379 pvData = (void *)m_pvClipboardBuf.wait();
380 if ( cbData != m_cbClipboardBuf.defaults()
381 && pvData != (void *)m_pvClipboardBuf.defaults())
382 {
383 pPacket = (vbcl::ipc::clipboard::data_packet_t *)RTMemAllocZ(sizeof(vbcl::ipc::clipboard::data_packet_t) + cbData);
384 if (RT_VALID_PTR(pPacket))
385 {
386 pPacket->Hdr.u64Crc = 0;
387 pPacket->Hdr.uSessionId = uSessionId;
388 pPacket->Hdr.idCmd = CLIP_DATA;
389 pPacket->Hdr.cbData = sizeof(vbcl::ipc::clipboard::data_packet_t) + cbData;
390 pPacket->cbData = cbData;
391
392 memcpy((uint8_t *)pPacket + sizeof(vbcl::ipc::clipboard::data_packet_t), pvData, cbData);
393 rc = vbcl::ipc::packet_write(hIpcSession, &pPacket->Hdr);
394 RTMemFree(pPacket);
395 }
396 else
397 rc = VERR_NO_MEMORY;
398 }
399 else
400 rc = VERR_TIMEOUT;
401
402 VBClLogVerbose(3, "%s: send_data [sid=%u, cbData=%u], rc=%Rrc\n",
403 m_fServer ? "server" : "client", uSessionId, cbData, rc);
404
405 return rc;
406}
407
408int vbcl::ipc::clipboard::ClipboardIpc::recv_data(uint32_t uSessionId, RTLOCALIPCSESSION hIpcSession)
409{
410 int rc;
411 vbcl::ipc::clipboard::data_packet_t *pPacket;
412 vbcl::ipc::command_t idCmd = CMD_UNKNOWN;
413 uint32_t cbData = 0;
414
415 rc = vbcl::ipc::packet_read(uSessionId, hIpcSession, (void **)&pPacket);
416 if (RT_SUCCESS(rc))
417 {
418 if ( pPacket->Hdr.idCmd == CLIP_DATA
419 && vbcl::ipc::packet_verify(&pPacket->Hdr, pPacket->Hdr.cbData))
420 {
421 void *pvData = RTMemAllocZ(pPacket->cbData);
422 idCmd = pPacket->Hdr.idCmd;
423 if (RT_VALID_PTR(pvData))
424 {
425 memcpy(pvData, (uint8_t *)pPacket + sizeof(vbcl::ipc::clipboard::data_packet_t), pPacket->cbData);
426 m_pvClipboardBuf.set((uint64_t)pvData);
427 cbData = pPacket->cbData;
428 m_cbClipboardBuf.set(cbData);
429 }
430 else
431 rc = VERR_NO_MEMORY;
432 }
433 else
434 rc = VERR_WRONG_ORDER;
435
436 RTMemFree(pPacket);
437 }
438
439 VBClLogVerbose(3, "%s: recv_data [sid=%u, cmd=0x%x, cbData=%u], rc=%Rrc\n",
440 m_fServer ? "server" : "client", uSessionId, idCmd, cbData, rc);
441
442 return rc;
443}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use