VirtualBox

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

Last change on this file since 107755 was 106808, checked in by vboxsync, 4 months ago

Additions: Linux/Wayland: Add customizable prefix to IPC server sock name to destinguish between clipboard and DnD IPC sockets, bugref:10796.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 16.1 KB
Line 
1/* $Id: wayland-helper-ipc.h 106808 2024-10-31 14:20:11Z vboxsync $ */
2/** @file
3 * Guest Additions - Definitions for IPC between VBoxClient and vboxwl tool.
4 */
5
6/*
7 * Copyright (C) 2006-2024 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#ifndef GA_INCLUDED_SRC_x11_VBoxClient_wayland_helper_ipc_h
29#define GA_INCLUDED_SRC_x11_VBoxClient_wayland_helper_ipc_h
30#ifndef RT_WITHOUT_PRAGMA_ONCE
31# pragma once
32#endif
33
34#include <sys/types.h>
35#include <pwd.h>
36#include <unistd.h>
37
38#include <iprt/cdefs.h>
39#include <iprt/err.h>
40#include <iprt/linux/sysfs.h>
41#include <iprt/localipc.h>
42#include <iprt/mem.h>
43#include <iprt/crc.h>
44#include <iprt/env.h>
45#include <iprt/process.h>
46#include <iprt/asm.h>
47#include <iprt/time.h>
48#include <iprt/nocrt/new>
49
50#include <VBox/GuestHost/clipboard-helper.h>
51
52#include "VBoxClient.h"
53#include "wayland-helper.h"
54
55/** Path to Gtk helper tool which raises popup window and gets
56 * access to Wayland clipboard. */
57#ifndef VBOXWL_PATH
58# define VBOXWL_PATH "/usr/bin/vboxwl"
59#endif
60/** Limit maximum log verbosity level for popup tool. */
61#define VBOXWL_VERBOSITY_MAX (5)
62
63/** IPC server socket name prefixes. */
64#define VBOXWL_SRV_NAME_PREFIX_CLIP "clip"
65
66/** Arguments to vboxwl tool. */
67#define VBOXWL_ARG_CLIP_HG_COPY "--clip-hg-copy"
68#define VBOXWL_ARG_CLIP_GH_ANNOUNCE "--clip-gh-announce"
69#define VBOXWL_ARG_CLIP_GH_COPY "--clip-gh-copy"
70#define VBOXWL_ARG_SESSION_ID "--session-id"
71
72/** Time in milliseconds to wait for IPC socket events. */
73#define VBOX_GTKIPC_RX_TIMEOUT_MS (VBCL_WAYLAND_DATA_WAIT_TIMEOUT_MS)
74
75namespace vbcl
76{
77 namespace ipc
78 {
79 /** List of commands which VBoxClient and vboxwl use for IPC communication. */
80 typedef enum
81 {
82 /** Initializer. */
83 CMD_UNKNOWN = 0,
84 /** Send or receive list of clipboard formats which
85 * host or guest announces. */
86 VBOX_FORMATS,
87 /** Send or receive a clipboard format which host
88 * or guest requests. */
89 VBOX_FORMAT,
90 /** Send or receive clipboard data in given format. */
91 VBOX_DATA,
92 /** Termination of commands list. */
93 CMD_MAX
94 } command_t;
95
96 /** IPC command flow direction: from VBoxClient to vboxwl. */
97 const bool FLOW_DIRECTION_CLIENT = false;
98 /** IPC command flow direction: from vboxwl to VBoxClient. */
99 const bool FLOW_DIRECTION_SERVER = true;
100
101 /** IPC flow entry. */
102 typedef struct
103 {
104 /** Command ID. */
105 command_t enmCmd;
106 /** Flow direction. */
107 bool fDirection;
108 } flow_t;
109
110 /** IPC command header. */
111 typedef struct
112 {
113 /** IPC command packet checksum, includes header and payload. */
114 uint64_t u64Crc;
115 /** IPC session ID. Generated by VBoxClient instance and
116 * provided to vboxwl tool as a command line argument. Needs to be
117 * checked by both parties when data is received over IPC. */
118 uint32_t uSessionId;
119 /** IPC command identificator (opaque). */
120 command_t idCmd;
121 /** Size of payload data. */
122 uint64_t cbData;
123
124 } packet_t;
125
126 /**
127 * Log IPC packet content.
128 *
129 * @param pPacket Pointer to IPC packet data.
130 */
131 void packet_dump(vbcl::ipc::packet_t *pPacket);
132
133 /**
134 * Verify IPC packet integrity.
135 *
136 * @returns True if packet integrity check passed, False otherwise.
137 * @param pPacket Pointer to buffer which contains raw IPC packet data.
138 * @param cbPacket Size of buffer.
139 */
140 bool packet_verify(vbcl::ipc::packet_t *pPacket, size_t cbPacket);
141
142 /**
143 * Read entire packet from IPC socket.
144 *
145 * @returns IPRT status code. In case if success, output IPC packet
146 * is validated and its fields, such as packet size, can be trusted.
147 * @param uSessionId IPC session ID.
148 * @param hSession IPC session handle.
149 * @param ppvData Output buffer structured as validated
150 * IPC packet (contains size inside).
151 */
152 int packet_read(uint32_t uSessionId, RTLOCALIPCSESSION hSession, void **ppvData);
153
154 /**
155 * Write entire IPC packet into IPC socket.
156 *
157 * @returns IPRT status code.
158 * @param hSession IPC session handle.
159 * @param pPacket IPC packet.
160 */
161 int packet_write(RTLOCALIPCSESSION hSession, vbcl::ipc::packet_t *pPacket);
162
163 namespace data
164 {
165 /** Payload for IPC commands VBOX_FORMATS and VBOX_FORMAT. */
166 typedef struct
167 {
168 /** IPC command header. */
169 vbcl::ipc::packet_t Hdr;
170 /** Clipboard formats bitmask. */
171 SHCLFORMATS fFormats;
172 } formats_packet_t;
173
174 /** Payload for IPC command VBOX_DATA. */
175 typedef struct
176 {
177 /* IPC command header. */
178 vbcl::ipc::packet_t Hdr;
179 /** Clipboard buffer format. */
180 SHCLFORMAT uFmt;
181 /** Size of clipboard buffer data. */
182 uint64_t cbData;
183 } data_packet_t;
184
185 /**
186 * IPC commands flow is described as a table. Each entry of
187 * such table contains command ID and flow direction. Both
188 * sides, VBoxClient and vboxwl, go through exactly the same
189 * command flow table sequentially and depending on a role
190 * (client or server) either send or wait for data and receive
191 * it. When last table entry is reached by both sides
192 * (simultaneously) it means that IPC session is completed.
193 * If error occurs on either side in the middle of the flow,
194 * IPC session is aborted.
195 */
196
197 /** IPC flow description: Copy clipboard from host to guest. */
198 const flow_t HGCopyFlow[4] =
199 {
200 { VBOX_FORMATS, FLOW_DIRECTION_CLIENT },
201 { VBOX_FORMAT, FLOW_DIRECTION_SERVER },
202 { VBOX_DATA, FLOW_DIRECTION_CLIENT },
203 { CMD_MAX, false }
204 };
205
206 /** IPC flow description: Copy clipboard from guest to host. */
207 const flow_t GHCopyFlow[3] =
208 {
209 { VBOX_FORMAT, FLOW_DIRECTION_CLIENT },
210 { VBOX_DATA, FLOW_DIRECTION_SERVER },
211 { CMD_MAX, false }
212 };
213
214 /** IPC flow description: Announce guest's clipboard to the host
215 * and copy it to the host in format selected by host. */
216 const flow_t GHAnnounceAndCopyFlow[4] =
217 {
218 { VBOX_FORMATS, FLOW_DIRECTION_SERVER },
219 { VBOX_FORMAT, FLOW_DIRECTION_CLIENT },
220 { VBOX_DATA, FLOW_DIRECTION_SERVER },
221 { CMD_MAX, false }
222 };
223
224 class DataIpc
225 {
226 public:
227
228#ifdef RT_NEED_NEW_AND_DELETE
229 RTMEM_IMPLEMENT_NEW_AND_DELETE();
230#endif
231 DataIpc()
232 {}
233
234 /**
235 * Initialize memory.
236 *
237 * @param fServer Specify IPC role; if True, server role
238 * is assigned (set by VBoxClient),
239 * otherwise client role is assigned (vboxwl).
240 * @param uSessionId Unique IPC session ID (randomly generated
241 * by server).
242 */
243 void init(bool fServer, uint32_t uSessionId)
244 {
245 m_fFmts.init(VBOX_SHCL_FMT_NONE, VBCL_WAYLAND_VALUE_WAIT_TIMEOUT_MS);
246 m_uFmt.init(VBOX_SHCL_FMT_NONE, VBCL_WAYLAND_VALUE_WAIT_TIMEOUT_MS);
247 m_pvDataBuf.init(0, VBCL_WAYLAND_DATA_WAIT_TIMEOUT_MS);
248 m_cbDataBuf.init(0, VBCL_WAYLAND_DATA_WAIT_TIMEOUT_MS);
249 m_fServer = fServer;
250 m_uSessionId = uSessionId;
251 }
252
253 /**
254 * Reset IPC session data and free allocated resources.
255 */
256 void reset()
257 {
258 void *pvData = (void *)m_pvDataBuf.reset();
259 if (RT_VALID_PTR(pvData))
260 RTMemFree(pvData);
261
262 m_fFmts.reset();
263 m_uFmt.reset();
264 m_cbDataBuf.reset();
265 }
266
267 /**
268 * Process IPC flow from start to finish.
269 *
270 * @returns IPRT status code.
271 * @param pFlow Pointer to selected IPC flow.
272 * @param hIpcSession IPC connection handle.
273 */
274 int flow(const flow_t *pFlow, RTLOCALIPCSESSION hIpcSession)
275 {
276 int idx = 0;
277 int rc = VINF_SUCCESS;
278
279 while ( RT_SUCCESS(rc)
280 && pFlow[idx].enmCmd != CMD_MAX)
281 {
282 rc = select_fn(pFlow[idx].enmCmd, pFlow[idx].fDirection, hIpcSession);
283 idx++;
284 }
285
286 return rc;
287 }
288
289 /** IPC session internal data. */
290 Waitable<volatile SHCLFORMATS> m_fFmts;
291 Waitable<volatile SHCLFORMAT> m_uFmt;
292 Waitable<volatile uint64_t> m_pvDataBuf;
293 Waitable<volatile uint32_t> m_cbDataBuf;
294
295 protected:
296
297 /**
298 * Send available clipboard formats over IPC.
299 *
300 * @returns IPRT status code.
301 * @param uSessionId IPC session ID.
302 * @param hIpcSession IPC connection handle.
303 */
304 int send_formats(uint32_t uSessionId, RTLOCALIPCSESSION hIpcSession);
305
306 /**
307 * Receive available clipboard formats over IPC.
308 *
309 * @returns IPRT status code.
310 * @param uSessionId IPC session ID.
311 * @param hIpcSession IPC connection handle.
312 */
313 int recv_formats(uint32_t uSessionId, RTLOCALIPCSESSION hIpcSession);
314
315 /**
316 * Send requested clipboard format over IPC.
317 *
318 * @returns IPRT status code.
319 * @param uSessionId IPC session ID.
320 * @param hIpcSession IPC connection handle.
321 */
322 int send_format(uint32_t uSessionId, RTLOCALIPCSESSION hIpcSession);
323
324 /**
325 * Receive requested clipboard format over IPC.
326 *
327 * @returns IPRT status code.
328 * @param uSessionId IPC session ID.
329 * @param hIpcSession IPC connection handle.
330 */
331 int recv_format(uint32_t uSessionId, RTLOCALIPCSESSION hIpcSession);
332
333 /**
334 * Send clipboard buffer over IPC.
335 *
336 * @returns IPRT status code.
337 * @param uSessionId IPC session ID.
338 * @param hIpcSession IPC connection handle.
339 */
340 int send_data(uint32_t uSessionId, RTLOCALIPCSESSION hIpcSession);
341
342 /**
343 * Receive clipboard buffer over IPC.
344 *
345 * @returns IPRT status code.
346 * @param uSessionId IPC session ID.
347 * @param hIpcSession IPC connection handle.
348 */
349 int recv_data(uint32_t uSessionId, RTLOCALIPCSESSION hIpcSession);
350
351 /**
352 * Take one step flow action.
353 *
354 * Taking into account given command and IPC role, either
355 * send or receive data from IPC socket.
356 *
357 * @returns IPRT status code.
358 * @param enmCmd IPC command ID.
359 * @param fDirection IPC role.
360 * @param hIpcSession IPC connection handle.
361 */
362 int select_fn(command_t enmCmd, bool fDirection, RTLOCALIPCSESSION hIpcSession)
363 {
364 int rc = VERR_INVALID_PARAMETER;
365 bool fShouldSend;
366
367 if (m_fServer)
368 fShouldSend = (fDirection == FLOW_DIRECTION_CLIENT);
369 else
370 fShouldSend = (fDirection == FLOW_DIRECTION_SERVER);
371
372 switch(enmCmd)
373 {
374 case VBOX_FORMATS:
375 {
376 if (fShouldSend)
377 rc = send_formats(m_uSessionId, hIpcSession);
378 else
379 rc = recv_formats(m_uSessionId, hIpcSession);
380 break;
381 }
382
383 case VBOX_FORMAT:
384 {
385 if (fShouldSend)
386 rc = send_format(m_uSessionId, hIpcSession);
387 else
388 rc = recv_format(m_uSessionId, hIpcSession);
389 break;
390 }
391
392 case VBOX_DATA:
393 {
394 if (fShouldSend)
395 rc = send_data(m_uSessionId, hIpcSession);
396 else
397 rc = recv_data(m_uSessionId, hIpcSession);
398 break;
399 }
400
401 default:
402 break;
403 }
404
405 return rc;
406 }
407
408 bool m_fServer;
409 uint32_t m_uSessionId;
410 };
411 }
412 }
413}
414
415/**
416 * Helper function to get Gtk helper IPC server name.
417 *
418 * This function should be used by both IPC server and client code
419 * in order to connect one to another. Output string will be in
420 * format: GtkHlpIpcServer-&lt;prefix&gt;--&lt;active tty&gt;-&lt;user name&gt;.
421 *
422 * @returns IPRT status code.
423 * @param szNamePrefix Name prefix.
424 * @param szBuf Where to store generated name string.
425 * @param cbBuf Size of buffer.
426 */
427RTDECL(int) vbcl_wayland_hlp_gtk_ipc_srv_name(const char *szNamePrefix, char *szBuf, size_t cbBuf);
428
429#endif /* !GA_INCLUDED_SRC_x11_VBoxClient_wayland_helper_ipc_h */
430
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette