VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp@ 100381

Last change on this file since 100381 was 100381, checked in by vboxsync, 23 months ago

Shared Clipboard: Linux build fixes. bugref:9437

  • Property svn:eol-style set to native
  • Property svn:keyword set to Id
  • Property svn:keywords set to Author Date Id Revision
File size: 106.1 KB
Line 
1/* $Id: VBoxGuestR3LibClipboard.cpp 100381 2023-07-05 09:15:19Z vboxsync $ */
2/** @file
3 * VBoxGuestR3Lib - Ring-3 Support Library for VirtualBox guest additions, Shared Clipboard.
4 */
5
6/*
7 * Copyright (C) 2007-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.215389.xyz.
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 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <VBox/GuestHost/SharedClipboard.h>
42#include <VBox/GuestHost/clipboard-helper.h>
43#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
44# include <VBox/GuestHost/SharedClipboard-transfers.h>
45#endif
46#include <VBox/HostServices/VBoxClipboardSvc.h>
47#include <VBox/err.h>
48#include <iprt/assert.h>
49#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
50# include <iprt/dir.h>
51# include <iprt/file.h>
52# include <iprt/path.h>
53#endif
54#include <iprt/string.h>
55#include <iprt/cpp/ministring.h>
56
57#ifdef LOG_GROUP
58 #undef LOG_GROUP
59#endif
60#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
61#include <VBox/log.h>
62
63#include "VBoxGuestR3LibInternal.h"
64
65
66/*
67 * Function naming convention:
68 *
69 * FunctionNameRecv = Receives a host message (request).
70 * FunctionNameReply = Replies to a host message (request).
71 * FunctionNameSend = Sends a guest message to the host.
72 */
73
74
75/*********************************************************************************************************************************
76* Prototypes *
77*********************************************************************************************************************************/
78
79
80/**
81 * Connects to the Shared Clipboard service, legacy version, do not use anymore.
82 *
83 * @returns VBox status code
84 * @param pidClient Where to put the client id on success. The client id
85 * must be passed to all the other clipboard calls.
86 */
87VBGLR3DECL(int) VbglR3ClipboardConnect(HGCMCLIENTID *pidClient)
88{
89 int rc = VbglR3HGCMConnect("VBoxSharedClipboard", pidClient);
90 if (RT_FAILURE(rc))
91 {
92 if (rc == VERR_HGCM_SERVICE_NOT_FOUND)
93 LogRel(("Shared Clipboard: Unabled to connect, as host service was not found, skipping\n"));
94 else
95 LogRel(("Shared Clipboard: Unabled to connect to host service, rc=%Rrc\n", rc));
96 }
97 LogFlowFuncLeaveRC(rc);
98 return rc;
99}
100
101
102/**
103 * Connects to the Shared Clipboard service, extended version.
104 *
105 * @returns VBox status code.
106 * @param pCtx Command context. This will be initialized by this
107 * call.
108 * @param fGuestFeatures The guest features supported by this client,
109 * VBOX_SHCL_GF_0_XXX.
110 */
111VBGLR3DECL(int) VbglR3ClipboardConnectEx(PVBGLR3SHCLCMDCTX pCtx, uint64_t fGuestFeatures)
112{
113 /*
114 * Intialize the context structure.
115 */
116 pCtx->idClient = 0;
117 pCtx->fGuestFeatures = fGuestFeatures;
118 pCtx->fHostFeatures = 0;
119 pCtx->fUseLegacyProtocol = true;
120 pCtx->idContext = 0;
121
122#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
123 /* Init callback table. */
124 RT_ZERO(pCtx->Transfers.Callbacks);
125 /* Indicate that this guest supports Shared Clipboard file transfers. */
126 pCtx->fGuestFeatures |= VBOX_SHCL_GF_0_TRANSFERS;
127# ifdef RT_OS_WINDOWS
128 /* Indicate that on Windows guest OSes we have our own IDataObject implementation which
129 * integrates nicely into the guest's Windows Explorer showing / handling the Shared Clipboard file transfers. */
130 pCtx->fGuestFeatures |= VBOX_SHCL_GF_0_TRANSFERS_FRONTEND;
131# endif
132 pCtx->Transfers.cbChunkSize = VBOX_SHCL_DEFAULT_CHUNK_SIZE; /** @todo Make this configurable. */
133 pCtx->Transfers.cbMaxChunkSize = VBOX_SHCL_MAX_CHUNK_SIZE; /** @todo Ditto. */
134#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
135
136 /*
137 * First step is connecting to the HGCM service.
138 */
139 int rc = VbglR3ClipboardConnect(&pCtx->idClient);
140 if (RT_SUCCESS(rc))
141 {
142 /*
143 * Next is reporting our features. If this fails, assume older host.
144 */
145 rc = VbglR3ClipboardReportFeatures(pCtx->idClient, pCtx->fGuestFeatures, &pCtx->fHostFeatures);
146 if (RT_SUCCESS(rc))
147 {
148 LogRel2(("Shared Clipboard: Guest features: %#RX64 - Host features: %#RX64\n",
149 pCtx->fGuestFeatures, pCtx->fHostFeatures));
150
151 if ( (pCtx->fHostFeatures & VBOX_SHCL_HF_0_CONTEXT_ID)
152 && (pCtx->fGuestFeatures & VBOX_SHCL_GF_0_CONTEXT_ID) )
153 {
154 pCtx->fUseLegacyProtocol = false;
155
156#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
157 if ( (pCtx->fHostFeatures & VBOX_SHCL_HF_0_TRANSFERS)
158 && (pCtx->fGuestFeatures & VBOX_SHCL_GF_0_TRANSFERS) )
159 {
160 VBoxShClParmNegotiateChunkSize MsgChunkSize;
161 do
162 {
163 VBGL_HGCM_HDR_INIT(&MsgChunkSize.hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_NEGOTIATE_CHUNK_SIZE,
164 VBOX_SHCL_CPARMS_NEGOTIATE_CHUNK_SIZE);
165 MsgChunkSize.cb32MaxChunkSize.SetUInt32(pCtx->Transfers.cbMaxChunkSize);
166 MsgChunkSize.cb32ChunkSize.SetUInt32(0); /* If set to 0, let the host choose. */
167 rc = VbglR3HGCMCall(&MsgChunkSize.hdr, sizeof(MsgChunkSize));
168 } while (rc == VERR_INTERRUPTED);
169 if (RT_SUCCESS(rc))
170 {
171 Assert(MsgChunkSize.cb32ChunkSize.type == VMMDevHGCMParmType_32bit);
172 pCtx->Transfers.cbChunkSize = RT_MIN(MsgChunkSize.cb32ChunkSize.u.value32, pCtx->Transfers.cbChunkSize);
173 Assert(MsgChunkSize.cb32MaxChunkSize.type == VMMDevHGCMParmType_32bit);
174 pCtx->Transfers.cbMaxChunkSize = RT_MIN(MsgChunkSize.cb32MaxChunkSize.u.value32, pCtx->Transfers.cbMaxChunkSize);
175
176 LogRel2(("Shared Clipboard: Using chunk size %RU32 (maximum is %RU32)\n",
177 pCtx->Transfers.cbChunkSize, pCtx->Transfers.cbMaxChunkSize));
178 }
179 }
180 else
181 {
182 if (!(pCtx->fHostFeatures & VBOX_SHCL_HF_0_TRANSFERS))
183 LogRel(("Shared Clipboard: Host does not support transfers\n"));
184 }
185#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
186 }
187 else
188 {
189 if (!(pCtx->fHostFeatures & VBOX_SHCL_HF_0_CONTEXT_ID))
190 LogRel(("Shared Clipboard: Host does not support context IDs, using legacy protocol\n"));
191
192 pCtx->fUseLegacyProtocol = true;
193 }
194 }
195 else
196 {
197 AssertLogRelMsg(rc == VERR_NOT_SUPPORTED || rc == VERR_NOT_IMPLEMENTED,
198 ("Reporting features failed: %Rrc\n", rc));
199 pCtx->fUseLegacyProtocol = true;
200 }
201 }
202
203 LogFlowFuncLeaveRC(rc);
204 return rc;
205}
206
207
208/**
209 * Reports features to the host and retrieve host feature set.
210 *
211 * @returns VBox status code.
212 * @param idClient The client ID returned by VbglR3ClipboardConnect().
213 * @param fGuestFeatures Features to report, VBOX_SHCL_GF_XXX.
214 * @param pfHostFeatures Where to store the features VBOX_SHCL_HF_XXX.
215 */
216VBGLR3DECL(int) VbglR3ClipboardReportFeatures(uint32_t idClient, uint64_t fGuestFeatures, uint64_t *pfHostFeatures)
217{
218 int rc;
219 do
220 {
221 struct
222 {
223 VBGLIOCHGCMCALL Hdr;
224 HGCMFunctionParameter f64Features0;
225 HGCMFunctionParameter f64Features1;
226 } Msg;
227 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_REPORT_FEATURES, 2);
228 VbglHGCMParmUInt64Set(&Msg.f64Features0, fGuestFeatures);
229 VbglHGCMParmUInt64Set(&Msg.f64Features1, VBOX_SHCL_GF_1_MUST_BE_ONE);
230
231 rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
232 if (RT_SUCCESS(rc))
233 {
234 Assert(Msg.f64Features0.type == VMMDevHGCMParmType_64bit);
235 Assert(Msg.f64Features1.type == VMMDevHGCMParmType_64bit);
236 if (Msg.f64Features1.u.value64 & VBOX_SHCL_GF_1_MUST_BE_ONE)
237 rc = VERR_NOT_SUPPORTED;
238 else if (pfHostFeatures)
239 *pfHostFeatures = Msg.f64Features0.u.value64;
240 break;
241 }
242 } while (rc == VERR_INTERRUPTED);
243 return rc;
244
245}
246
247
248/**
249 * Disconnects from the Shared Clipboard service, legacy version, do not use anymore.
250 *
251 * @returns VBox status code.
252 * @param idClient The client id returned by VbglR3ClipboardConnect().
253 */
254VBGLR3DECL(int) VbglR3ClipboardDisconnect(HGCMCLIENTID idClient)
255{
256 return VbglR3HGCMDisconnect(idClient);
257}
258
259
260/**
261 * Disconnects from the Shared Clipboard service, extended version.
262 *
263 * @returns VBox status code.
264 * @param pCtx Shared Clipboard command context to use for the connection.
265 */
266VBGLR3DECL(int) VbglR3ClipboardDisconnectEx(PVBGLR3SHCLCMDCTX pCtx)
267{
268 int rc = VbglR3ClipboardDisconnect(pCtx->idClient);
269 if (RT_SUCCESS(rc))
270 {
271 pCtx->idClient = 0;
272 }
273
274 LogFlowFuncLeaveRC(rc);
275 return rc;
276}
277
278
279/**
280 * Receives reported formats from the host.
281 *
282 * @returns VBox status code.
283 * @param pCtx Shared Clipboard command context to use for the
284 * connection.
285 * @param pfFormats Where to store the received formats from the host.
286 */
287static int vbglR3ClipboardFormatsReportRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLFORMATS pfFormats)
288{
289 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
290 AssertPtrReturn(pfFormats, VERR_INVALID_POINTER);
291
292 *pfFormats = 0;
293
294 struct
295 {
296 VBGLIOCHGCMCALL Hdr;
297 HGCMFunctionParameter id64Context;
298 HGCMFunctionParameter f32Formats;
299 } Msg;
300
301 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_GET, 2);
302 Msg.id64Context.SetUInt32(VBOX_SHCL_HOST_MSG_FORMATS_REPORT);
303 Msg.f32Formats.SetUInt32(0);
304
305 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
306 if (RT_SUCCESS(rc))
307 {
308 rc = Msg.f32Formats.GetUInt32(pfFormats);
309 AssertRC(rc);
310 }
311
312 LogFlowFuncLeaveRC(rc);
313 return rc;
314}
315
316
317/**
318 * Fetches a VBOX_SHCL_HOST_MSG_READ_DATA_CID message.
319 *
320 * @returns VBox status code.
321 * @param pCtx Shared Clipboard command context to use for the connection.
322 * @param pfFormat Where to return the requested format.
323 */
324static int vbglR3ClipboardFetchReadDataCid(PVBGLR3SHCLCMDCTX pCtx, PSHCLFORMAT pfFormat)
325{
326 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
327 AssertPtrReturn(pfFormat, VERR_INVALID_POINTER);
328
329 struct
330 {
331 VBGLIOCHGCMCALL Hdr;
332 HGCMFunctionParameter id64Context;
333 HGCMFunctionParameter f32Format;
334 } Msg;
335
336 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_GET, 2);
337 Msg.id64Context.SetUInt64(VBOX_SHCL_HOST_MSG_READ_DATA_CID);
338 Msg.f32Format.SetUInt32(0);
339
340 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
341 if (RT_SUCCESS(rc))
342 {
343 rc = Msg.id64Context.GetUInt64(&pCtx->idContext);
344 AssertRC(rc);
345 int rc2 = Msg.f32Format.GetUInt32(pfFormat);
346 AssertRCStmt(rc2, rc = rc2);
347 }
348
349 LogFlowFuncLeaveRC(rc);
350 return rc;
351}
352
353
354/**
355 * Fetches a VBOX_SHCL_HOST_MSG_READ_DATA message.
356 *
357 * @returns VBox status code.
358 * @param pCtx Shared Clipboard command context to use for the connection.
359 * @param pfFormat Where to return the requested format.
360 */
361static int vbglR3ClipboardFetchReadData(PVBGLR3SHCLCMDCTX pCtx, PSHCLFORMAT pfFormat)
362{
363 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
364 AssertPtrReturn(pfFormat, VERR_INVALID_POINTER);
365
366 struct
367 {
368 VBGLIOCHGCMCALL Hdr;
369 HGCMFunctionParameter id32Msg;
370 HGCMFunctionParameter f32Format;
371 } Msg;
372
373 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_GET, 2);
374 Msg.id32Msg.SetUInt32(VBOX_SHCL_HOST_MSG_READ_DATA);
375 Msg.f32Format.SetUInt32(0);
376
377 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
378 if (RT_SUCCESS(rc))
379 {
380 rc = Msg.f32Format.GetUInt32(pfFormat);
381 AssertRC(rc);
382 }
383
384 LogFlowFuncLeaveRC(rc);
385 return rc;
386}
387
388
389/**
390 * Get a host message, legacy version (which does not have VBOX_SHCL_GUEST_FN_MSG_GET). Do not use anymore.
391 *
392 * Note: This is the old message which still is being used for the non-URI Shared Clipboard transfers,
393 * to not break compatibility with older additions / VBox versions.
394 *
395 * This will block until a message becomes available.
396 *
397 * @returns VBox status code.
398 * @param idClient The client id returned by VbglR3ClipboardConnect().
399 * @param pidMsg Where to store the message id.
400 * @param pfFormats Where to store the format(s) the message applies to.
401 */
402VBGLR3DECL(int) VbglR3ClipboardGetHostMsgOld(HGCMCLIENTID idClient, uint32_t *pidMsg, uint32_t *pfFormats)
403{
404 VBoxShClGetHostMsgOld Msg;
405
406 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, VBOX_SHCL_CPARMS_GET_HOST_MSG_OLD);
407 VbglHGCMParmUInt32Set(&Msg.msg, 0);
408 VbglHGCMParmUInt32Set(&Msg.formats, 0);
409
410 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
411 if (RT_SUCCESS(rc))
412 {
413 int rc2 = VbglHGCMParmUInt32Get(&Msg.msg, pidMsg);
414 if (RT_SUCCESS(rc))
415 {
416 rc2 = VbglHGCMParmUInt32Get(&Msg.formats, pfFormats);
417 if (RT_SUCCESS(rc2))
418 return rc;
419 }
420 rc = rc2;
421 }
422 *pidMsg = UINT32_MAX - 1;
423 *pfFormats = UINT32_MAX;
424 return rc;
425}
426
427
428/**
429 * Reads data from the host clipboard.
430 *
431 * @returns VBox status code.
432 * @retval VINF_BUFFER_OVERFLOW If there is more data available than the caller provided buffer space for.
433 *
434 * @param idClient The client id returned by VbglR3ClipboardConnect().
435 * @param fFormat The format we're requesting the data in.
436 * @param pvData Where to store the data.
437 * @param cbData The size of the buffer pointed to by \a pvData.
438 * This also indicates the maximum size to read.
439 * @param pcbRead The actual size of the host clipboard data. May be larger than \a cbData.
440 */
441VBGLR3DECL(int) VbglR3ClipboardReadData(HGCMCLIENTID idClient, uint32_t fFormat, void *pvData, uint32_t cbData,
442 uint32_t *pcbRead)
443{
444 LogFlowFunc(("fFormat=%#x, pvData=%p, cbData=%RU32\n", fFormat, pvData, cbData));
445
446 struct
447 {
448 VBGLIOCHGCMCALL Hdr;
449 VBoxShClParmDataRead Parms;
450 } Msg;
451
452 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_DATA_READ, VBOX_SHCL_CPARMS_DATA_READ);
453 VbglHGCMParmUInt32Set(&Msg.Parms.f32Format, fFormat);
454 VbglHGCMParmPtrSet( &Msg.Parms.pData, pvData, cbData);
455 VbglHGCMParmUInt32Set(&Msg.Parms.cb32Needed, 0);
456
457 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
458 if (RT_SUCCESS(rc))
459 {
460 uint32_t cbRead;
461 rc = VbglHGCMParmUInt32Get(&Msg.Parms.cb32Needed, &cbRead);
462 if (RT_SUCCESS(rc))
463 {
464 LogFlowFunc(("cbRead=%RU32\n", cbRead));
465
466 if (cbRead > cbData)
467 rc = VINF_BUFFER_OVERFLOW;
468
469 *pcbRead = cbRead;
470 }
471 }
472
473 LogFlowFuncLeaveRC(rc);
474 return rc;
475}
476
477
478/**
479 * Reads clipboard data from the host clipboard.
480 *
481 * @returns VBox status code.
482 * @retval VINF_BUFFER_OVERFLOW If there is more data available than the caller provided buffer space for.
483 *
484 * @param pCtx The command context returned by VbglR3ClipboardConnectEx().
485 * @param uFormat Clipboard format of clipboard data to be read.
486 * @param pvData Buffer where to store the read data.
487 * @param cbData Size (in bytes) of data buffer where to store the read data.
488 * @param pcbRead The actual size of the host clipboard data.
489 */
490VBGLR3DECL(int) VbglR3ClipboardReadDataEx(PVBGLR3SHCLCMDCTX pCtx,
491 SHCLFORMAT uFormat, void *pvData, uint32_t cbData, uint32_t *pcbRead)
492{
493 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
494 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
495 return VbglR3ClipboardReadData(pCtx->idClient, uFormat, pvData, cbData, pcbRead);
496}
497
498
499/**
500 * Query the host features.
501 *
502 * @returns VBox status code.
503 * @param idClient The client ID returned by VbglR3ClipboardConnect().
504 * @param pfHostFeatures Where to store the host feature, VBOX_SHCL_HF_XXX.
505 */
506VBGLR3DECL(int) VbglR3ClipboardQueryFeatures(uint32_t idClient, uint64_t *pfHostFeatures)
507{
508 int rc;
509 do
510 {
511 struct
512 {
513 VBGLIOCHGCMCALL Hdr;
514 HGCMFunctionParameter f64Features0;
515 HGCMFunctionParameter f64Features1;
516 } Msg;
517 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_QUERY_FEATURES, 2);
518 VbglHGCMParmUInt64Set(&Msg.f64Features0, 0);
519 VbglHGCMParmUInt64Set(&Msg.f64Features1, RT_BIT_64(63));
520
521 rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
522 if (RT_SUCCESS(rc))
523 {
524 Assert(Msg.f64Features0.type == VMMDevHGCMParmType_64bit);
525 Assert(Msg.f64Features1.type == VMMDevHGCMParmType_64bit);
526 if (Msg.f64Features1.u.value64 & RT_BIT_64(63))
527 rc = VERR_NOT_SUPPORTED;
528 else if (pfHostFeatures)
529 *pfHostFeatures = Msg.f64Features0.u.value64;
530 break;
531 }
532 } while (rc == VERR_INTERRUPTED);
533 return rc;
534
535}
536
537/**
538 * Peeks at the next host message, extended version.
539 *
540 * This glosses over the difference between new (6.1) and old (1.3.2) host
541 * service versions, however it does so by abusing @a pcParameters, so don't use
542 * it directly when in legacy mode, always pass it on to
543 * VbglR3ClipboardEventGetNext() or VbglR3ClipboardEventGetNextEx().
544 *
545 * @returns VBox status code.
546 * @retval VERR_INTERRUPTED if interrupted. Does the necessary cleanup, so
547 * caller just have to repeat this call.
548 * @retval VERR_VM_RESTORED if the VM has been restored (idRestoreCheck).
549 * @retval VERR_TRY_AGAIN if no new message is available.
550 *
551 * @param pCtx Shared Clipboard command context to use for the connection.
552 * @param fWait Wait for new messages to arrive if \c true, return immediately if \c false.
553 * @param pidMsg Where to store the message id.
554 * @param pcParameters Where to store the number of parameters which will
555 * be received in a second call to the host.
556 * @param pidRestoreCheck Pointer to the VbglR3GetSessionId() variable to use
557 * for the VM restore check. Optional.
558 *
559 * @note Restore check is only performed optimally with a 6.0 host.
560 */
561static int vbglR3ClipboardMsgPeekEx(PVBGLR3SHCLCMDCTX pCtx, bool fWait, uint32_t *pidMsg,
562 uint32_t *pcParameters, uint64_t *pidRestoreCheck)
563{
564 AssertPtrReturn(pidMsg, VERR_INVALID_POINTER);
565 AssertPtrReturn(pcParameters, VERR_INVALID_POINTER);
566
567 struct
568 {
569 VBGLIOCHGCMCALL Hdr;
570 HGCMFunctionParameter idMsg; /* Doubles as restore check on input. */
571 HGCMFunctionParameter cParameters;
572 } Msg;
573 int rc;
574 if (!pCtx->fUseLegacyProtocol)
575 {
576 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient,
577 fWait ? VBOX_SHCL_GUEST_FN_MSG_PEEK_WAIT
578 : VBOX_SHCL_GUEST_FN_MSG_PEEK_NOWAIT, 2);
579 VbglHGCMParmUInt64Set(&Msg.idMsg, pidRestoreCheck ? *pidRestoreCheck : 0);
580 VbglHGCMParmUInt32Set(&Msg.cParameters, 0);
581 rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
582 Log4Func(("VbglR3HGCMCall -> %Rrc\n", rc));
583 if (RT_SUCCESS(rc))
584 {
585 AssertMsgReturn( Msg.idMsg.type == VMMDevHGCMParmType_64bit
586 && Msg.cParameters.type == VMMDevHGCMParmType_32bit,
587 ("msg.type=%d num_parms.type=%d\n", Msg.idMsg.type, Msg.cParameters.type),
588 VERR_INTERNAL_ERROR_3);
589
590 *pidMsg = (uint32_t)Msg.idMsg.u.value64;
591 *pcParameters = Msg.cParameters.u.value32;
592 return rc;
593 }
594
595 /*
596 * If restored, update pidRestoreCheck.
597 */
598 if (rc == VERR_VM_RESTORED && pidRestoreCheck)
599 *pidRestoreCheck = Msg.idMsg.u.value64;
600 }
601 else
602 {
603 /*
604 * We do some crude stuff here by putting the 2nd parameter (foramts) in the parameter count,
605 * however it's supposed to be passed directly to VbglR3ClipboardEventGetNext or
606 * VbglR3ClipboardEventGetNextEx, so that's fine...
607 */
608 rc = VbglR3ClipboardGetHostMsgOld(pCtx->idClient, pidMsg, pcParameters);
609 if (RT_SUCCESS(rc))
610 return rc;
611 }
612
613 /*
614 * If interrupted we must cancel the call so it doesn't prevent us from making another one.
615 */
616 if (rc == VERR_INTERRUPTED)
617 {
618 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_CANCEL, 0);
619 int rc2 = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg.Hdr));
620 AssertRC(rc2);
621 }
622
623 *pidMsg = UINT32_MAX - 1;
624 *pcParameters = UINT32_MAX - 2;
625 return rc;
626}
627
628/**
629 * Peeks at the next host message, waiting for one to turn up.
630 *
631 * This glosses over the difference between new (6.1) and old (1.3.2) host
632 * service versions, however it does so by abusing @a pcParameters, so don't use
633 * it directly when in legacy mode, always pass it on to
634 * VbglR3ClipboardEventGetNext() or VbglR3ClipboardEventGetNextEx().
635 *
636 * @returns VBox status code.
637 * @retval VERR_INTERRUPTED if interrupted. Does the necessary cleanup, so
638 * caller just have to repeat this call.
639 * @retval VERR_VM_RESTORED if the VM has been restored (idRestoreCheck).
640 *
641 * @param pCtx Shared Clipboard command context to use for the connection.
642 * @param pidMsg Where to store the message id.
643 * @param pcParameters Where to store the number of parameters which will
644 * be received in a second call to the host.
645 * @param pidRestoreCheck Pointer to the VbglR3GetSessionId() variable to use
646 * for the VM restore check. Optional.
647 *
648 * @note Restore check is only performed optimally with a 6.0 host.
649 */
650VBGLR3DECL(int) VbglR3ClipboardMsgPeekWait(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pidMsg,
651 uint32_t *pcParameters, uint64_t *pidRestoreCheck)
652{
653 return vbglR3ClipboardMsgPeekEx(pCtx, true /* fWait */, pidMsg, pcParameters, pidRestoreCheck);
654}
655
656/**
657 * Peeks at the next host message, returning immediately.
658 *
659 * This glosses over the difference between new (6.1) and old (1.3.2) host
660 * service versions, however it does so by abusing @a pcParameters, so don't use
661 * it directly when in legacy mode, always pass it on to
662 * VbglR3ClipboardEventGetNext() or VbglR3ClipboardEventGetNextEx().
663 *
664 * @returns VBox status code.
665 * @retval VERR_INTERRUPTED if interrupted. Does the necessary cleanup, so
666 * caller just have to repeat this call.
667 * @retval VERR_VM_RESTORED if the VM has been restored (idRestoreCheck).
668 * @retval VERR_TRY_AGAIN if no new message is available.
669 *
670 * @param pCtx Shared Clipboard command context to use for the connection.
671 * @param pidMsg Where to store the message id.
672 * @param pcParameters Where to store the number of parameters which will
673 * be received in a second call to the host.
674 * @param pidRestoreCheck Pointer to the VbglR3GetSessionId() variable to use
675 * for the VM restore check. Optional.
676 *
677 * @note Restore check is only performed optimally with a 6.0 host.
678 */
679VBGLR3DECL(int) VbglR3ClipboardMsgPeek(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pidMsg,
680 uint32_t *pcParameters, uint64_t *pidRestoreCheck)
681{
682 return vbglR3ClipboardMsgPeekEx(pCtx, false /* fWait */, pidMsg, pcParameters, pidRestoreCheck);
683}
684
685#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
686
687/**
688 * Reads a transfer root list header from the host.
689 *
690 * @returns VBox status code.
691 * @param pCtx Shared Clipboard command context to use for the connection.
692 * @param pRootListHdr Where to store the received root list header.
693 */
694static int vbglR3ClipboardTransferRootListHdrRead(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHDR pRootListHdr)
695{
696 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
697 AssertPtrReturn(pRootListHdr, VERR_INVALID_POINTER);
698
699 VBoxShClRootListHdrMsg Msg;
700
701 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
702 VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_READ, VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ);
703
704 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
705 Msg.ReqParms.fRoots.SetUInt32(0);
706
707 Msg.cRoots.SetUInt64(0);
708
709 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
710 if (RT_SUCCESS(rc))
711 {
712 rc = Msg.ReqParms.fRoots.GetUInt32(&pRootListHdr->fFeatures); AssertRC(rc);
713 if (RT_SUCCESS(rc))
714 {
715 rc = Msg.cRoots.GetUInt64(&pRootListHdr->cEntries);
716 AssertRC(rc);
717
718 pRootListHdr->cbTotalSize = 0; /* Unused for the root list header. */
719 }
720 }
721 else
722 LogRel(("Shared Clipboard: Reading root list header failed: %Rrc\n", rc));
723
724 LogFlowFuncLeaveRC(rc);
725 return rc;
726}
727
728/**
729 * Reads a transfer root list entry from the host.
730 *
731 * @returns VBox status code.
732 * @param pCtx Shared Clipboard command context to use for the connection.
733 * @param uIndex Index of root list entry to read.
734 * @param pRootListEntry Where to store the root list entry read from the host.
735 */
736static int vbglR3ClipboardTransferRootListEntryRead(PVBGLR3SHCLCMDCTX pCtx, uint64_t uIndex, PSHCLLISTENTRY pRootListEntry)
737{
738 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
739 AssertPtrReturn(pRootListEntry, VERR_INVALID_POINTER);
740
741 VBoxShClRootListEntryMsg Msg;
742
743 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
744 VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_READ, VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ);
745
746 uint32_t const fInfo = VBOX_SHCL_INFO_F_FSOBJINFO; /* For now the only info we have. */
747
748 Msg.Parms.uContext.SetUInt64(pCtx->idContext);
749 Msg.Parms.fInfo.SetUInt32(fInfo);
750 Msg.Parms.uIndex.SetUInt64(uIndex);
751
752 char szName[SHCLLISTENTRY_MAX_NAME];
753 Msg.szName.SetPtr(szName, sizeof(szName));
754
755 void *pvInfo = NULL;
756 uint32_t cbInfo = 0;
757
758 int rc = VINF_SUCCESS;
759
760 if ((fInfo & VBOX_SHCL_INFO_F_FSOBJINFO) == VBOX_SHCL_INFO_F_FSOBJINFO)
761 {
762 cbInfo = sizeof(SHCLFSOBJINFO);
763 pvInfo = RTMemAlloc(cbInfo);
764 if (!pvInfo)
765 rc = VERR_NO_MEMORY;
766 }
767
768 if (RT_SUCCESS(rc))
769 {
770 Msg.cbInfo.SetUInt32(cbInfo);
771 Msg.pvInfo.SetPtr(pvInfo, cbInfo);
772
773 rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
774 if (RT_SUCCESS(rc))
775 {
776 uint32_t fInfoRet;
777 rc = Msg.Parms.fInfo.GetUInt32(&fInfoRet);
778 AssertRCReturn(rc, rc);
779 AssertMsgStmt((fInfoRet & VBOX_SHCL_INFO_F_FSOBJINFO) == VBOX_SHCL_INFO_F_FSOBJINFO,
780 ("Host returned unknown entry info flags (%#x)\n", fInfoRet), rc = VERR_INVALID_PARAMETER);
781 if (RT_SUCCESS(rc))
782 {
783 uint32_t cbInfoRet = 0;
784 Msg.cbInfo.GetUInt32(&cbInfoRet);
785
786 AssertMsgStmt(cbInfo == cbInfoRet,
787 ("Host reported cbInfo %RU32, expected %RU32\n", cbInfoRet, cbInfo), rc = VERR_INVALID_PARAMETER);
788
789 rc = ShClTransferListEntryInitEx(pRootListEntry, fInfo, szName, pvInfo, cbInfo);
790 if (RT_SUCCESS(rc))
791 {
792 pvInfo = NULL; /* Entry took ownership of pvInfo now. */
793 cbInfo = 0;
794 }
795 }
796 }
797 else
798 LogRel(("Shared Clipboard: Reading root list entry failed: %Rrc\n", rc));
799 }
800
801 RTMemFree(pvInfo);
802
803 LogFlowFuncLeaveRC(rc);
804 return rc;
805}
806
807/**
808 * Reads the transfer root list from the host.
809 *
810 * @returns VBox status code.
811 * @param pCtx Shared Clipboard command context to use for the connection.
812 * @param pTransfer Transfer to read root list for.
813 * Must be in INITIALIZED state.
814 */
815VBGLR3DECL(int) VbglR3ClipboardTransferRootListRead(PVBGLR3SHCLCMDCTX pCtx, PSHCLTRANSFER pTransfer)
816{
817 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
818 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
819
820 AssertMsgReturn(ShClTransferGetStatus(pTransfer) == SHCLTRANSFERSTATUS_INITIALIZED,
821 ("Can't read root list -- wrong transfer status\n"), VERR_WRONG_ORDER);
822
823 SHCLLISTHDR Hdr;
824 int rc = vbglR3ClipboardTransferRootListHdrRead(pCtx, &Hdr);
825 if (RT_SUCCESS(rc))
826 {
827 LogFlowFunc(("cEntries=%RU64, cTotalSize=%RU64\n", Hdr.cEntries, Hdr.cbTotalSize));
828
829 if (!Hdr.cEntries) /* Should never happen (tm). */
830 {
831#ifdef DEBUG_andy
832 AssertFailed();
833#endif
834 LogRel(("Shared Clipboard: Warning: Transfer %RU32 has no entries\n", ShClTransferGetID(pTransfer)));
835 }
836
837 for (uint64_t i = 0; i < Hdr.cEntries; i++)
838 {
839 PSHCLLISTENTRY pEntry = NULL;
840 rc = ShClTransferListEntryAlloc(&pEntry);
841 if (RT_SUCCESS(rc))
842 {
843 rc = vbglR3ClipboardTransferRootListEntryRead(pCtx, i, pEntry);
844 if (RT_SUCCESS(rc))
845 rc = ShClTransferListAddEntry(&pTransfer->lstRoots, pEntry, true /* fAppend */);
846 }
847
848 if (RT_FAILURE(rc))
849 {
850 ShClTransferListEntryFree(pEntry);
851 break;
852 }
853 }
854 }
855 else
856 LogRel(("Shared Clipboard: Reading root list for transfer %RU32 failed: %Rrc\n", ShClTransferGetID(pTransfer), rc));
857
858 LogFlowFuncLeaveRC(rc);
859 return rc;
860}
861
862/**
863 * Receives a transfer status from the host.
864 *
865 * @returns VBox status code.
866 * @param pCtx Shared Clipboard command context to use for the connection.
867 * @param pEnmDir Where to store the transfer direction for the reported transfer.
868 * @param pReport Where to store the transfer (status) report.
869 */
870VBGLR3DECL(int) VbglR3ClipboarTransferStatusRecv(PVBGLR3SHCLCMDCTX pCtx,
871 PSHCLTRANSFERDIR pEnmDir, PSHCLTRANSFERREPORT pReport)
872{
873 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
874 AssertPtrReturn(pReport, VERR_INVALID_POINTER);
875 AssertPtrReturn(pEnmDir, VERR_INVALID_POINTER);
876
877 VBoxShClTransferStatusMsg Msg;
878 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
879 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_TRANSFER_STATUS);
880
881 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_STATUS);
882 Msg.enmDir.SetUInt32(0);
883 Msg.enmStatus.SetUInt32(0);
884 Msg.rc.SetUInt32(0);
885 Msg.fFlags.SetUInt32(0);
886
887 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
888 if (RT_SUCCESS(rc))
889 {
890 rc = Msg.uContext.GetUInt64(&pCtx->idContext); AssertRC(rc);
891 if (RT_SUCCESS(rc))
892 {
893 rc = Msg.enmDir.GetUInt32((uint32_t *)pEnmDir);
894 AssertRC(rc);
895 }
896 if (RT_SUCCESS(rc))
897 {
898 rc = Msg.enmStatus.GetUInt32(&pReport->uStatus);
899 AssertRC(rc);
900 }
901 if (RT_SUCCESS(rc))
902 {
903 rc = Msg.rc.GetUInt32((uint32_t *)&pReport->rc);
904 AssertRC(rc);
905 }
906 if (RT_SUCCESS(rc))
907 {
908 rc = Msg.fFlags.GetUInt32(&pReport->fFlags);
909 AssertRC(rc);
910 }
911 }
912
913 LogFlowFuncLeaveRC(rc);
914 return rc;
915}
916
917/**
918 * Replies to a transfer report from the host, extended version.
919 *
920 * @returns VBox status code.
921 * @param pCtx Shared Clipboard command context to use for the connection.
922 * @param uCID Context ID to use.
923 * The transfer ID is part of this.
924 * @param uStatus Tranfer status to reply.
925 * @param rcTransfer Result code (rc) to reply.
926 */
927static int vbglR3ClipboardTransferStatusReplyEx(PVBGLR3SHCLCMDCTX pCtx, uint64_t uCID,
928 SHCLTRANSFERSTATUS uStatus, int rcTransfer)
929{
930 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
931
932 VBoxShClReplyMsg Msg;
933 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
934 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
935
936 Msg.uContext.SetUInt64(uCID);
937 Msg.enmType.SetUInt32(VBOX_SHCL_TX_REPLYMSGTYPE_TRANSFER_STATUS);
938 Msg.rc.SetUInt32((uint32_t )rcTransfer); /* int vs. uint32_t */
939 Msg.pvPayload.SetPtr(NULL, 0);
940
941 Msg.u.TransferStatus.enmStatus.SetUInt32((uint32_t)uStatus);
942
943 LogFlowFunc(("%s\n", ShClTransferStatusToStr(uStatus)));
944
945 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
946
947 LogFlowFuncLeaveRC(rc);
948 return rc;
949}
950
951/**
952 * Replies to a transfer report from the host.
953 *
954 * @returns VBox status code.
955 * @param pCtx Shared Clipboard command context to use for the connection.
956 * @param pTransfer Transfer of report to reply to.
957 * @param uStatus Tranfer status to reply.
958 * @param rcTransfer Result code (rc) to reply.
959 */
960VBGLR3DECL(int) VbglR3ClipboardTransferStatusReply(PVBGLR3SHCLCMDCTX pCtx, PSHCLTRANSFER pTransfer,
961 SHCLTRANSFERSTATUS uStatus, int rcTransfer)
962{
963 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
964 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
965
966 int rc = vbglR3ClipboardTransferStatusReplyEx(pCtx, pCtx->idContext, uStatus, rcTransfer);
967
968 LogFlowFuncLeaveRC(rc);
969 return rc;
970}
971
972/**
973 * Receives a host request to read a transfer root list header from the guest.
974 *
975 * @returns VBox status code.
976 * @param pCtx Shared Clipboard command context to use for the connection.
977 * @param pfRoots Where to store the root list header flags to use, requested by the host.
978 */
979VBGLR3DECL(int) VbglR3ClipboardTransferRootListHdrReadReq(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pfRoots)
980{
981 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
982 AssertPtrReturn(pfRoots, VERR_INVALID_POINTER);
983
984 VBoxShClRootListReadReqMsg Msg;
985 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
986 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ_REQ);
987
988 Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ);
989 Msg.ReqParms.fRoots.SetUInt32(0);
990
991 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
992 if (RT_SUCCESS(rc))
993 {
994 rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext); AssertRC(rc);
995 if (RT_SUCCESS(rc))
996 {
997 rc = Msg.ReqParms.fRoots.GetUInt32(pfRoots);
998 AssertRC(rc);
999 }
1000 }
1001
1002 LogFlowFuncLeaveRC(rc);
1003 return rc;
1004}
1005
1006/**
1007 * Replies to a transfer root list header request.
1008 *
1009 * @returns VBox status code.
1010 * @param pCtx Shared Clipboard command context to use for the connection.
1011 * @param pRootListHdr Root lsit header to reply to the host.
1012 */
1013VBGLR3DECL(int) VbglR3ClipboardTransferRootListHdrReadReply(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHDR pRootListHdr)
1014{
1015 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1016 AssertPtrReturn(pRootListHdr, VERR_INVALID_POINTER);
1017
1018 VBoxShClRootListHdrMsg Msg;
1019 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1020 VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_WRITE, VBOX_SHCL_CPARMS_ROOT_LIST_HDR_WRITE);
1021
1022 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1023 Msg.ReqParms.fRoots.SetUInt32(pRootListHdr->fFeatures);
1024
1025 Msg.cRoots.SetUInt64(pRootListHdr->cEntries);
1026
1027 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1028
1029 LogFlowFuncLeaveRC(rc);
1030 return rc;
1031}
1032
1033/**
1034 * Receives a host request to read a transfer root list entry from the guest.
1035 *
1036 * @returns VBox status code.
1037 * @param pCtx Shared Clipboard command context to use for the connection.
1038 * @param puIndex Where to return the index of the root list entry the host wants to read.
1039 * @param pfInfo Where to return the read flags the host wants to use.
1040 */
1041VBGLR3DECL(int) VbglR3ClipboardTransferRootListEntryReadReq(PVBGLR3SHCLCMDCTX pCtx, uint64_t *puIndex, uint32_t *pfInfo)
1042{
1043 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1044 AssertPtrReturn(puIndex, VERR_INVALID_POINTER);
1045 AssertPtrReturn(pfInfo, VERR_INVALID_POINTER);
1046
1047 VBoxShClRootListEntryReadReqMsg Msg;
1048 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1049 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ_REQ);
1050
1051 Msg.Parms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ);
1052 Msg.Parms.fInfo.SetUInt32(0);
1053 Msg.Parms.uIndex.SetUInt64(0);
1054
1055 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1056 if (RT_SUCCESS(rc))
1057 {
1058 rc = Msg.Parms.uContext.GetUInt64(&pCtx->idContext); AssertRC(rc);
1059 if (RT_SUCCESS(rc))
1060 {
1061 rc = Msg.Parms.fInfo.GetUInt32(pfInfo);
1062 AssertRC(rc);
1063 }
1064 if (RT_SUCCESS(rc))
1065 {
1066 rc = Msg.Parms.uIndex.GetUInt64(puIndex);
1067 AssertRC(rc);
1068 }
1069 }
1070
1071 LogFlowFuncLeaveRC(rc);
1072 return rc;
1073}
1074
1075/**
1076 * Replies to a transfer root list entry read request from the host.
1077 *
1078 * @returns VBox status code.
1079 * @param pCtx Shared Clipboard command context to use for the connection.
1080 * @param uIndex Index of root list entry to reply.
1081 * @param pEntry Actual root list entry to reply.
1082 */
1083VBGLR3DECL(int) VbglR3ClipboardTransferRootListEntryReadReply(PVBGLR3SHCLCMDCTX pCtx, uint32_t uIndex, PSHCLLISTENTRY pEntry)
1084{
1085 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1086 AssertPtrReturn(pEntry, VERR_INVALID_POINTER);
1087
1088 VBoxShClRootListEntryMsg Msg;
1089 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1090 VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_WRITE, VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_WRITE);
1091
1092 Msg.Parms.uContext.SetUInt64(pCtx->idContext);
1093 Msg.Parms.fInfo.SetUInt32(pEntry->fInfo);
1094 Msg.Parms.uIndex.SetUInt64(uIndex);
1095
1096 Msg.szName.SetPtr(pEntry->pszName, pEntry->cbName);
1097 Msg.cbInfo.SetUInt32(pEntry->cbInfo);
1098 Msg.pvInfo.SetPtr(pEntry->pvInfo, pEntry->cbInfo);
1099
1100 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1101
1102 LogFlowFuncLeaveRC(rc);
1103 return rc;
1104}
1105
1106/**
1107 * Sends a request to open a transfer list handle to the host.
1108 *
1109 * @returns VBox status code.
1110 * @param pCtx Shared Clipboard command context to use for the connection.
1111 * @param pOpenParms List open parameters to use for the open request.
1112 * @param phList Where to return the list handle received from the host.
1113 */
1114VBGLR3DECL(int) VbglR3ClipboardTransferListOpenSend(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTOPENPARMS pOpenParms,
1115 PSHCLLISTHANDLE phList)
1116{
1117 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1118 AssertPtrReturn(pOpenParms, VERR_INVALID_POINTER);
1119 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1120
1121 VBoxShClListOpenMsg Msg;
1122 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1123 VBOX_SHCL_GUEST_FN_LIST_OPEN, VBOX_SHCL_CPARMS_LIST_OPEN);
1124
1125 Msg.uContext.SetUInt64(pCtx->idContext);
1126 Msg.fList.SetUInt32(0);
1127 Msg.pvFilter.SetPtr(pOpenParms->pszFilter, pOpenParms->cbFilter);
1128 Msg.pvPath.SetPtr(pOpenParms->pszPath, pOpenParms->cbPath);
1129 Msg.uHandle.SetUInt64(0);
1130
1131 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1132 if (RT_SUCCESS(rc))
1133 {
1134 rc = Msg.uHandle.GetUInt64(phList); AssertRC(rc);
1135 }
1136
1137 LogFlowFuncLeaveRC(rc);
1138 return rc;
1139}
1140
1141/**
1142 * Receives a host request to open a transfer list handle on the guest.
1143 *
1144 * @returns VBox status code.
1145 * @param pCtx Shared Clipboard command context to use for the connection.
1146 * @param pOpenParms Where to store the open parameters the host wants to use for opening the list handle.
1147 */
1148VBGLR3DECL(int) VbglR3ClipboardTransferListOpenRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTOPENPARMS pOpenParms)
1149{
1150 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1151 AssertPtrReturn(pOpenParms, VERR_INVALID_POINTER);
1152
1153 VBoxShClListOpenMsg Msg;
1154 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1155 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_OPEN);
1156
1157 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN);
1158 Msg.fList.SetUInt32(0);
1159 Msg.pvPath.SetPtr(pOpenParms->pszPath, pOpenParms->cbPath);
1160 Msg.pvFilter.SetPtr(pOpenParms->pszFilter, pOpenParms->cbFilter);
1161 Msg.uHandle.SetUInt64(0);
1162
1163 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1164 if (RT_SUCCESS(rc))
1165 {
1166 rc = Msg.uContext.GetUInt64(&pCtx->idContext);
1167 if (RT_SUCCESS(rc))
1168 rc = Msg.fList.GetUInt32(&pOpenParms->fList);
1169 }
1170
1171 LogFlowFuncLeaveRC(rc);
1172 return rc;
1173}
1174
1175/**
1176 * Replies to a transfer list open request from the host.
1177 *
1178 * @returns VBox status code.
1179 * @param pCtx Shared Clipboard command context to use for the connection.
1180 * @param rcReply Return code to reply to the host.
1181 * @param hList List handle of (guest) list to reply to the host.
1182 */
1183VBGLR3DECL(int) VbglR3ClipboardTransferListOpenReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLLISTHANDLE hList)
1184{
1185 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1186
1187 VBoxShClReplyMsg Msg;
1188 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1189 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1190
1191 Msg.uContext.SetUInt64(pCtx->idContext);
1192 Msg.enmType.SetUInt32(VBOX_SHCL_TX_REPLYMSGTYPE_LIST_OPEN);
1193 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1194 Msg.pvPayload.SetPtr(NULL, 0);
1195
1196 Msg.u.ListOpen.uHandle.SetUInt64(hList);
1197
1198 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1199
1200 LogFlowFuncLeaveRC(rc);
1201 return rc;
1202}
1203
1204/**
1205 * Receives a host request to close a list handle on the guest.
1206 *
1207 * @returns VBox status code.
1208 * @param pCtx Shared Clipboard command context to use for the connection.
1209 * @param phList Where to store the list handle to close, received from the host.
1210 */
1211VBGLR3DECL(int) VbglR3ClipboardTransferListCloseRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList)
1212{
1213 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1214 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1215
1216 VBoxShClListCloseMsg Msg;
1217 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1218 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_CLOSE);
1219
1220 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE);
1221 Msg.uHandle.SetUInt64(0);
1222
1223 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1224 if (RT_SUCCESS(rc))
1225 {
1226 rc = Msg.uContext.GetUInt64(&pCtx->idContext);
1227 if (RT_SUCCESS(rc))
1228 {
1229 rc = Msg.uHandle.GetUInt64(phList);
1230 AssertRC(rc);
1231 }
1232 }
1233
1234 LogFlowFuncLeaveRC(rc);
1235 return rc;
1236}
1237
1238/**
1239 * Replies to a transfer list handle close request from the host.
1240 *
1241 * @returns VBox status code.
1242 * @param pCtx Shared Clipboard command context to use for the connection.
1243 * @param rcReply Return code to reply to the host.
1244 * @param hList List handle the send the close reply for.
1245 */
1246VBGLR3DECL(int) VbglR3ClipboardTransferListCloseReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLLISTHANDLE hList)
1247{
1248 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1249
1250 VBoxShClReplyMsg Msg;
1251 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1252 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1253
1254 Msg.uContext.SetUInt64(pCtx->idContext);
1255 Msg.enmType.SetUInt32(VBOX_SHCL_TX_REPLYMSGTYPE_LIST_CLOSE);
1256 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1257 Msg.pvPayload.SetPtr(NULL, 0);
1258
1259 Msg.u.ListOpen.uHandle.SetUInt64(hList);
1260
1261 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1262
1263 LogFlowFuncLeaveRC(rc);
1264 return rc;
1265}
1266
1267/**
1268 * Sends a request to close a transfer list handle to the host.
1269 *
1270 * @returns VBox status code.
1271 * @param pCtx Shared Clipboard command context to use for the connection.
1272 * @param hList List handle to request for closing on the host.
1273 */
1274VBGLR3DECL(int) VbglR3ClipboardTransferListCloseSend(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList)
1275{
1276 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1277
1278 VBoxShClListCloseMsg Msg;
1279 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1280 VBOX_SHCL_GUEST_FN_LIST_CLOSE, VBOX_SHCL_CPARMS_LIST_CLOSE);
1281
1282 Msg.uContext.SetUInt64(pCtx->idContext);
1283 Msg.uHandle.SetUInt64(hList);
1284
1285 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1286
1287 LogFlowFuncLeaveRC(rc);
1288 return rc;
1289}
1290
1291/**
1292 * Sends a request to read a transfer list header to the host.
1293 *
1294 * @returns VBox status code.
1295 * @param pCtx Shared Clipboard command context to use for the connection.
1296 * @param hList List handle to read list header for.
1297 * @param fFlags List header read flags to use.
1298 * @param pListHdr Where to return the list header received from the host.
1299 */
1300VBGLR3DECL(int) VbglR3ClipboardTransferListHdrRead(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList, uint32_t fFlags,
1301 PSHCLLISTHDR pListHdr)
1302{
1303 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1304 AssertPtrReturn(pListHdr, VERR_INVALID_POINTER);
1305
1306 VBoxShClListHdrMsg Msg;
1307 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1308 VBOX_SHCL_GUEST_FN_LIST_HDR_READ, VBOX_SHCL_CPARMS_LIST_HDR);
1309
1310 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1311 Msg.ReqParms.uHandle.SetUInt64(hList);
1312 Msg.ReqParms.fFlags.SetUInt32(fFlags);
1313
1314 Msg.fFeatures.SetUInt32(0);
1315 Msg.cbTotalSize.SetUInt32(0);
1316 Msg.cTotalObjects.SetUInt64(0);
1317 Msg.cbTotalSize.SetUInt64(0);
1318
1319 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1320 if (RT_SUCCESS(rc))
1321 {
1322 rc = Msg.fFeatures.GetUInt32(&pListHdr->fFeatures);
1323 if (RT_SUCCESS(rc))
1324 rc = Msg.cTotalObjects.GetUInt64(&pListHdr->cEntries);
1325 if (RT_SUCCESS(rc))
1326 rc = Msg.cbTotalSize.GetUInt64(&pListHdr->cbTotalSize);
1327 }
1328
1329 LogFlowFuncLeaveRC(rc);
1330 return rc;
1331}
1332
1333/**
1334 * Receives a host request to read a transfer list header on the guest.
1335 *
1336 * @returns VBox status code.
1337 * @param pCtx Shared Clipboard command context to use for the connection.
1338 * @param phList Where to return the list handle to read list header for.
1339 * @param pfFlags Where to return the List header read flags to use.
1340 */
1341VBGLR3DECL(int) VbglR3ClipboardTransferListHdrReadRecvReq(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList, uint32_t *pfFlags)
1342{
1343 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1344 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1345 AssertPtrReturn(pfFlags, VERR_INVALID_POINTER);
1346
1347 VBoxShClListHdrReadReqMsg Msg;
1348 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1349 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_HDR_READ_REQ);
1350
1351 Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ);
1352 Msg.ReqParms.uHandle.SetUInt64(0);
1353 Msg.ReqParms.fFlags.SetUInt32(0);
1354
1355 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1356 if (RT_SUCCESS(rc))
1357 {
1358 rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext);
1359 if (RT_SUCCESS(rc))
1360 rc = Msg.ReqParms.uHandle.GetUInt64(phList);
1361 if (RT_SUCCESS(rc))
1362 rc = Msg.ReqParms.fFlags.GetUInt32(pfFlags);
1363 }
1364
1365 LogFlowFuncLeaveRC(rc);
1366 return rc;
1367}
1368
1369/**
1370 * Sends (writes) a transfer list header to the host.
1371 *
1372 * @returns VBox status code.
1373 * @param pCtx Shared Clipboard command context to use for the connection.
1374 * @param hList List handle to write list header for.
1375 * @param pListHdr List header to write.
1376 */
1377VBGLR3DECL(int) VbglR3ClipboardTransferListHdrWrite(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList,
1378 PSHCLLISTHDR pListHdr)
1379{
1380 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1381 AssertPtrReturn(pListHdr, VERR_INVALID_POINTER);
1382
1383 VBoxShClListHdrMsg Msg;
1384 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1385 VBOX_SHCL_GUEST_FN_LIST_HDR_WRITE, VBOX_SHCL_CPARMS_LIST_HDR);
1386
1387 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1388 Msg.ReqParms.uHandle.SetUInt64(hList);
1389 Msg.ReqParms.fFlags.SetUInt32(0);
1390
1391 Msg.fFeatures.SetUInt32(0);
1392 Msg.cbTotalSize.SetUInt32(pListHdr->fFeatures);
1393 Msg.cTotalObjects.SetUInt64(pListHdr->cEntries);
1394 Msg.cbTotalSize.SetUInt64(pListHdr->cbTotalSize);
1395
1396 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1397
1398 LogFlowFuncLeaveRC(rc);
1399 return rc;
1400}
1401
1402/**
1403 * Sends a request to read a transfer list entry from the host.
1404 *
1405 * @returns VBox status code.
1406 * @param pCtx Shared Clipboard command context to use for the connection.
1407 * @param hList List handle to request to read a list entry for.
1408 * @param pListEntry Where to return the list entry read from the host.
1409 */
1410VBGLR3DECL(int) VbglR3ClipboardTransferListEntryRead(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList,
1411 PSHCLLISTENTRY pListEntry)
1412{
1413 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1414 AssertPtrReturn(pListEntry, VERR_INVALID_POINTER);
1415
1416 VBoxShClListEntryMsg Msg;
1417 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1418 VBOX_SHCL_GUEST_FN_LIST_ENTRY_READ, VBOX_SHCL_CPARMS_LIST_ENTRY);
1419
1420 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1421 Msg.ReqParms.uHandle.SetUInt64(hList);
1422 Msg.ReqParms.fInfo.SetUInt32(0);
1423
1424 Msg.szName.SetPtr(pListEntry->pszName, pListEntry->cbName);
1425 Msg.cbInfo.SetUInt32(pListEntry->cbInfo);
1426 Msg.pvInfo.SetPtr(pListEntry->pvInfo, pListEntry->cbInfo);
1427
1428 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1429 if (RT_SUCCESS(rc))
1430 {
1431 rc = Msg.cbInfo.GetUInt32(&pListEntry->cbInfo); AssertRC(rc);
1432 }
1433
1434 LogFlowFuncLeaveRC(rc);
1435 return rc;
1436}
1437
1438/**
1439 * Receives a host request to read a transfer list entry from the guest.
1440 *
1441 * @returns VBox status code.
1442 * @param pCtx Shared Clipboard command context to use for the connection.
1443 * @param phList Where to return the list handle to read a list entry for.
1444 * @param pfInfo Where to return the list read flags.
1445 */
1446VBGLR3DECL(int) VbglR3ClipboardTransferListEntryReadRecvReq(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList, uint32_t *pfInfo)
1447{
1448 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1449 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1450 AssertPtrReturn(pfInfo, VERR_INVALID_POINTER);
1451
1452 VBoxShClListEntryReadReqMsg Msg;
1453 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1454 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_ENTRY_READ);
1455
1456 Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ);
1457 Msg.ReqParms.uHandle.SetUInt64(0);
1458 Msg.ReqParms.fInfo.SetUInt32(0);
1459
1460 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1461 if (RT_SUCCESS(rc))
1462 {
1463 rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext);
1464 if (RT_SUCCESS(rc))
1465 {
1466 rc = Msg.ReqParms.uHandle.GetUInt64(phList);
1467 AssertRC(rc);
1468 }
1469 if (RT_SUCCESS(rc))
1470 {
1471 rc = Msg.ReqParms.fInfo.GetUInt32(pfInfo);
1472 AssertRC(rc);
1473 }
1474 }
1475
1476 LogFlowFuncLeaveRC(rc);
1477 return rc;
1478}
1479
1480/**
1481 * Sends (writes) a transfer list entry to the host.
1482 *
1483 * @returns VBox status code.
1484 * @param pCtx Shared Clipboard command context to use for the connection.
1485 * @param hList List handle to write a list etnry for.
1486 * @param pListEntry List entry to write.
1487 */
1488VBGLR3DECL(int) VbglR3ClipboardTransferListEntryWrite(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList,
1489 PSHCLLISTENTRY pListEntry)
1490{
1491 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1492 AssertPtrReturn(pListEntry, VERR_INVALID_POINTER);
1493
1494 VBoxShClListEntryMsg Msg;
1495 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1496 VBOX_SHCL_GUEST_FN_LIST_ENTRY_WRITE, VBOX_SHCL_CPARMS_LIST_ENTRY);
1497
1498 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1499 Msg.ReqParms.uHandle.SetUInt64(hList);
1500 Msg.ReqParms.fInfo.SetUInt32(pListEntry->fInfo);
1501
1502 Msg.szName.SetPtr(pListEntry->pszName, pListEntry->cbName);
1503 Msg.cbInfo.SetUInt32(pListEntry->cbInfo);
1504 Msg.pvInfo.SetPtr(pListEntry->pvInfo, pListEntry->cbInfo);
1505
1506 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1507
1508 LogFlowFuncLeaveRC(rc);
1509 return rc;
1510}
1511
1512/**
1513 * Receives a host request to open a transfer object on the guest.
1514 *
1515 * @returns VBox status code.
1516 * @param pCtx Shared Clipboard command context to use for the connection.
1517 * @param pCreateParms Where to store the object open/create parameters received from the host.
1518 */
1519VBGLR3DECL(int) VbglR3ClipboardTransferObjOpenRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms)
1520{
1521 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1522 AssertPtrReturn(pCreateParms, VERR_INVALID_POINTER);
1523
1524 VBoxShClObjOpenMsg Msg;
1525 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1526 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_OBJ_OPEN);
1527
1528 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN);
1529 Msg.uHandle.SetUInt64(0);
1530 Msg.szPath.SetPtr(pCreateParms->pszPath, pCreateParms->cbPath);
1531 Msg.fCreate.SetUInt32(0);
1532
1533 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1534 if (RT_SUCCESS(rc))
1535 {
1536 rc = Msg.uContext.GetUInt64(&pCtx->idContext);
1537 if (RT_SUCCESS(rc))
1538 rc = Msg.fCreate.GetUInt32(&pCreateParms->fCreate);
1539 }
1540
1541 LogFlowFuncLeaveRC(rc);
1542 return rc;
1543}
1544
1545/**
1546 * Replies a host request to open a transfer object.
1547 *
1548 * @returns VBox status code.
1549 * @param pCtx Shared Clipboard command context to use for the connection.
1550 * @param rcReply Return code to reply to the host.
1551 * @param hObj Object handle of opened object to reply to the host.
1552 */
1553VBGLR3DECL(int) VbglR3ClipboardTransferObjOpenReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLOBJHANDLE hObj)
1554{
1555 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1556
1557 VBoxShClReplyMsg Msg;
1558 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1559 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1560
1561 Msg.uContext.SetUInt64(pCtx->idContext);
1562 Msg.enmType.SetUInt32(VBOX_SHCL_TX_REPLYMSGTYPE_OBJ_OPEN);
1563 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1564 Msg.pvPayload.SetPtr(NULL, 0);
1565
1566 Msg.u.ObjOpen.uHandle.SetUInt64(hObj);
1567
1568 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1569
1570 LogFlowFuncLeaveRC(rc);
1571 return rc;
1572}
1573
1574/**
1575 * Sends a transfer object open request to the host.
1576 *
1577 * @returns VBox status code.
1578 * @param pCtx Shared Clipboard command context to use for the connection.
1579 * @param pCreateParms Object open/create parameters to use for opening the object on the host.
1580 * @param phObj Where to return the object handle from the host.
1581 */
1582VBGLR3DECL(int) VbglR3ClipboardTransferObjOpenSend(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms,
1583 PSHCLOBJHANDLE phObj)
1584{
1585 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1586 AssertPtrReturn(pCreateParms, VERR_INVALID_POINTER);
1587 AssertPtrReturn(phObj, VERR_INVALID_POINTER);
1588
1589 VBoxShClObjOpenMsg Msg;
1590 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1591 VBOX_SHCL_GUEST_FN_OBJ_OPEN, VBOX_SHCL_CPARMS_OBJ_OPEN);
1592
1593 Msg.uContext.SetUInt64(pCtx->idContext);
1594 Msg.uHandle.SetUInt64(0);
1595 Msg.szPath.SetPtr((void *)pCreateParms->pszPath, pCreateParms->cbPath);
1596 Msg.fCreate.SetUInt32(pCreateParms->fCreate);
1597
1598 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1599 if (RT_SUCCESS(rc))
1600 {
1601 Msg.uHandle.GetUInt64(phObj);
1602 }
1603
1604 LogFlowFuncLeaveRC(rc);
1605 return rc;
1606}
1607
1608/**
1609 * Receives a host request to close a transfer object on the guest.
1610 *
1611 * @returns VBox status code.
1612 * @param pCtx Shared Clipboard command context to use for the connection.
1613 * @param phObj Where to return the object handle to close from the host.
1614 */
1615VBGLR3DECL(int) VbglR3ClipboardTransferObjCloseRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJHANDLE phObj)
1616{
1617 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1618 AssertPtrReturn(phObj, VERR_INVALID_POINTER);
1619
1620 VBoxShClObjCloseMsg Msg;
1621 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1622 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_OBJ_CLOSE);
1623
1624 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE);
1625 Msg.uHandle.SetUInt64(0);
1626
1627 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1628 if (RT_SUCCESS(rc))
1629 {
1630 rc = Msg.uContext.GetUInt64(&pCtx->idContext);
1631 if (RT_SUCCESS(rc))
1632 rc = Msg.uHandle.GetUInt64(phObj);
1633 }
1634
1635 LogFlowFuncLeaveRC(rc);
1636 return rc;
1637}
1638
1639/**
1640 * Replies to a transfer object open request from the host.
1641 *
1642 * @returns VBox status code.
1643 * @param pCtx Shared Clipboard command context to use for the connection.
1644 * @param rcReply Return code to reply to the host.
1645 * @param hObj Object handle to reply to the host.
1646 */
1647VBGLR3DECL(int) VbglR3ClipboardTransferObjCloseReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLOBJHANDLE hObj)
1648{
1649 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1650
1651 VBoxShClReplyMsg Msg;
1652 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1653 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1654
1655 Msg.uContext.SetUInt64(pCtx->idContext);
1656 Msg.enmType.SetUInt32(VBOX_SHCL_TX_REPLYMSGTYPE_OBJ_CLOSE);
1657 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1658 Msg.pvPayload.SetPtr(NULL, 0);
1659
1660 Msg.u.ObjClose.uHandle.SetUInt64(hObj);
1661
1662 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1663
1664 LogFlowFuncLeaveRC(rc);
1665 return rc;
1666}
1667
1668/**
1669 * Sends a request to close a transfer object to the host.
1670 *
1671 * @returns VBox status code.
1672 * @param pCtx Shared Clipboard command context to use for the connection.
1673 * @param hObj Object handle to close on the host.
1674 */
1675VBGLR3DECL(int) VbglR3ClipboardTransferObjCloseSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj)
1676{
1677 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1678
1679 VBoxShClObjCloseMsg Msg;
1680 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1681 VBOX_SHCL_GUEST_FN_OBJ_CLOSE, VBOX_SHCL_CPARMS_OBJ_CLOSE);
1682
1683 Msg.uContext.SetUInt64(pCtx->idContext);
1684 Msg.uHandle.SetUInt64(hObj);
1685
1686 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1687
1688 LogFlowFuncLeaveRC(rc);
1689 return rc;
1690}
1691
1692/**
1693 * Receives a host request to read from a transfer object on the guest.
1694 *
1695 * @returns VBox status code.
1696 * @param pCtx Shared Clipboard command context to use for the connection.
1697 * @param phObj Where to return the object handle to read from.
1698 * @param pcbToRead Where to return the amount (in bytes) to read.
1699 * @param pfFlags Where to return the read flags.
1700 */
1701VBGLR3DECL(int) VbglR3ClipboardTransferObjReadRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJHANDLE phObj, uint32_t *pcbToRead,
1702 uint32_t *pfFlags)
1703{
1704 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1705 AssertPtrReturn(phObj, VERR_INVALID_POINTER);
1706 AssertPtrReturn(pcbToRead, VERR_INVALID_POINTER);
1707 AssertPtrReturn(pfFlags, VERR_INVALID_POINTER);
1708
1709 VBoxShClObjReadReqMsg Msg;
1710 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1711 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_OBJ_READ_REQ);
1712
1713 Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ);
1714 Msg.ReqParms.uHandle.SetUInt64(0);
1715 Msg.ReqParms.cbToRead.SetUInt32(0);
1716 Msg.ReqParms.fRead.SetUInt32(0);
1717
1718 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1719 if (RT_SUCCESS(rc))
1720 {
1721 rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext);
1722 if (RT_SUCCESS(rc))
1723 rc = Msg.ReqParms.uHandle.GetUInt64(phObj);
1724 if (RT_SUCCESS(rc))
1725 rc = Msg.ReqParms.cbToRead.GetUInt32(pcbToRead);
1726 if (RT_SUCCESS(rc))
1727 rc = Msg.ReqParms.fRead.GetUInt32(pfFlags);
1728 }
1729
1730 LogFlowFuncLeaveRC(rc);
1731 return rc;
1732}
1733
1734/**
1735 * Sends a request to read from a transfer object to the host.
1736 *
1737 * @returns VBox status code.
1738 * @param pCtx Shared Clipboard command context to use for the connection.
1739 * @param hObj Object handle of object to read from.
1740 * @param pvData Buffer where to store the read object data.
1741 * @param cbData Size (in bytes) of buffer.
1742 * @param pcbRead Where to store the amount (in bytes) read from the object.
1743 */
1744VBGLR3DECL(int) VbglR3ClipboardTransferObjReadSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj,
1745 void *pvData, uint32_t cbData, uint32_t *pcbRead)
1746{
1747 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1748 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1749 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1750 /* pcbRead is optional. */
1751
1752 VBoxShClObjReadWriteMsg Msg;
1753 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1754 VBOX_SHCL_GUEST_FN_OBJ_READ, VBOX_SHCL_CPARMS_OBJ_READ);
1755
1756 Msg.uContext.SetUInt64(pCtx->idContext);
1757 Msg.uHandle.SetUInt64(hObj);
1758 Msg.cbData.SetUInt32(cbData);
1759 Msg.pvData.SetPtr(pvData, cbData);
1760 Msg.cbChecksum.SetUInt32(0);
1761 Msg.pvChecksum.SetPtr(NULL, 0);
1762
1763 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1764 if (RT_SUCCESS(rc))
1765 {
1766 /** @todo Add checksum support. */
1767
1768 if (pcbRead)
1769 {
1770 rc = Msg.cbData.GetUInt32(pcbRead); AssertRC(rc);
1771 AssertReturn(cbData >= *pcbRead, VERR_TOO_MUCH_DATA);
1772 }
1773 }
1774
1775 LogFlowFuncLeaveRC(rc);
1776 return rc;
1777}
1778
1779/**
1780 * Sends a request to write to a transfer object to the host.
1781 *
1782 * @returns VBox status code.
1783 * @param pCtx Shared Clipboard command context to use for the connection.
1784 * @param hObj Object handle of object to write to.
1785 * @param pvData Buffer of data to write to object.
1786 * @param cbData Size (in bytes) of buffer.
1787 * @param pcbWritten Where to store the amount (in bytes) written to the object.
1788 */
1789VBGLR3DECL(int) VbglR3ClipboardTransferObjWriteSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj,
1790 void *pvData, uint32_t cbData, uint32_t *pcbWritten)
1791{
1792 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1793 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1794 /* cbData can be 0. */
1795 /* pcbWritten is optional. */
1796
1797 VBoxShClObjReadWriteMsg Msg;
1798 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1799 VBOX_SHCL_GUEST_FN_OBJ_WRITE, VBOX_SHCL_CPARMS_OBJ_WRITE);
1800
1801 Msg.uContext.SetUInt64(pCtx->idContext);
1802 Msg.uHandle.SetUInt64(hObj);
1803 Msg.cbData.SetUInt32(cbData);
1804 Msg.pvData.SetPtr(pvData, cbData);
1805 Msg.cbChecksum.SetUInt32(0);
1806 Msg.pvChecksum.SetPtr(NULL, 0);
1807
1808 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1809 if (RT_SUCCESS(rc))
1810 {
1811 /** @todo Add checksum support. */
1812
1813 if (pcbWritten)
1814 *pcbWritten = cbData; /** @todo For now return all as being written. */
1815 }
1816
1817 LogFlowFuncLeaveRC(rc);
1818 return rc;
1819}
1820
1821
1822/*********************************************************************************************************************************
1823* Transfer interface implementations *
1824*********************************************************************************************************************************/
1825
1826/** @copydoc SHCLTXPROVIDERIFACE::pfnRootListRead */
1827static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceRootListRead(PSHCLTXPROVIDERCTX pCtx)
1828{
1829 LogFlowFuncEnter();
1830
1831 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1832 AssertPtr(pCmdCtx);
1833
1834 int rc = VbglR3ClipboardTransferRootListRead(pCmdCtx, pCtx->pTransfer);
1835
1836 LogFlowFuncLeaveRC(rc);
1837 return rc;
1838}
1839
1840/** @copydoc SHCLTXPROVIDERIFACE::pfnListOpen */
1841static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceListOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLLISTOPENPARMS pOpenParms,
1842 PSHCLLISTHANDLE phList)
1843{
1844 LogFlowFuncEnter();
1845
1846 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1847 AssertPtr(pCmdCtx);
1848
1849 int rc = VbglR3ClipboardTransferListOpenSend(pCmdCtx, pOpenParms, phList);
1850
1851 LogFlowFuncLeaveRC(rc);
1852 return rc;
1853}
1854
1855/** @copydoc SHCLTXPROVIDERIFACE::pfnListClose */
1856static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceListClose(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList)
1857{
1858 LogFlowFuncEnter();
1859
1860 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1861 AssertPtr(pCmdCtx);
1862
1863 int rc = VbglR3ClipboardTransferListCloseSend(pCmdCtx, hList);
1864
1865 LogFlowFuncLeaveRC(rc);
1866 return rc;
1867}
1868
1869/** @copydoc SHCLTXPROVIDERIFACE::pfnListHdrRead */
1870static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceListHdrRead(PSHCLTXPROVIDERCTX pCtx,
1871 SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)
1872{
1873 LogFlowFuncEnter();
1874
1875 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1876 AssertPtr(pCmdCtx);
1877
1878 int rc = ShClTransferListHdrInit(pListHdr);
1879 if (RT_SUCCESS(rc))
1880 {
1881 if (RT_SUCCESS(rc))
1882 {
1883 rc = VbglR3ClipboardTransferListHdrRead(pCmdCtx, hList, 0 /* fFlags */, pListHdr);
1884 }
1885 else
1886 ShClTransferListHdrDestroy(pListHdr);
1887 }
1888
1889 LogFlowFuncLeaveRC(rc);
1890 return rc;
1891}
1892
1893/** @copydoc SHCLTXPROVIDERIFACE::pfnListEntryRead */
1894static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceListEntryRead(PSHCLTXPROVIDERCTX pCtx,
1895 SHCLLISTHANDLE hList, PSHCLLISTENTRY pListEntry)
1896{
1897 LogFlowFuncEnter();
1898
1899 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1900 AssertPtr(pCmdCtx);
1901
1902 int rc = VbglR3ClipboardTransferListEntryRead(pCmdCtx, hList, pListEntry);
1903
1904 LogFlowFuncLeaveRC(rc);
1905 return rc;
1906}
1907
1908/** @copydoc SHCLTXPROVIDERIFACE::pfnObjOpen */
1909static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceObjOpen(PSHCLTXPROVIDERCTX pCtx,
1910 PSHCLOBJOPENCREATEPARMS pCreateParms, PSHCLOBJHANDLE phObj)
1911{
1912 LogFlowFuncEnter();
1913
1914 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1915 AssertPtr(pCmdCtx);
1916
1917 int rc = VbglR3ClipboardTransferObjOpenSend(pCmdCtx, pCreateParms, phObj);
1918
1919 LogFlowFuncLeaveRC(rc);
1920 return rc;
1921}
1922
1923/** @copydoc SHCLTXPROVIDERIFACE::pfnObjClose */
1924static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceObjClose(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj)
1925{
1926 LogFlowFuncEnter();
1927
1928 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1929 AssertPtr(pCmdCtx);
1930
1931 int rc = VbglR3ClipboardTransferObjCloseSend(pCmdCtx, hObj);
1932
1933 LogFlowFuncLeaveRC(rc);
1934 return rc;
1935}
1936
1937/** @copydoc SHCLTXPROVIDERIFACE::pfnObjRead */
1938static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceObjRead(PSHCLTXPROVIDERCTX pCtx,
1939 SHCLOBJHANDLE hObj, void *pvData, uint32_t cbData,
1940 uint32_t fFlags, uint32_t *pcbRead)
1941{
1942 LogFlowFuncEnter();
1943
1944 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1945 AssertPtr(pCmdCtx);
1946
1947 RT_NOREF(fFlags); /* Not used yet. */
1948
1949 int rc = VbglR3ClipboardTransferObjReadSend(pCmdCtx, hObj, pvData, cbData, pcbRead);
1950
1951 LogFlowFuncLeaveRC(rc);
1952 return rc;
1953}
1954
1955/**
1956 * Creates (and registers) a transfer on the guest side.
1957 *
1958 * @returns VBox status code.
1959 * @param pCmdCtx Command context to use.
1960 * @param pTransferCtx Transfer context to init transfer for.
1961 * @param enmDir Specifies the transfer direction of this transfer.
1962 * @param enmSource Specifies the data source of the transfer.
1963 * @param idTransfer ID of transfer to create.
1964 * @param ppTransfer Where to return the transfer object on success. Optional.
1965 */
1966static int vbglR3ClipboardTransferCreate(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
1967 SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource, SHCLTRANSFERID idTransfer,
1968 PSHCLTRANSFER *ppTransfer)
1969{
1970 AssertReturn(idTransfer != NIL_SHCLTRANSFERID, VERR_WRONG_ORDER);
1971
1972 RT_NOREF(pCmdCtx);
1973
1974 PSHCLTRANSFER pTransfer;
1975 int rc = ShClTransferCreate(enmDir, enmSource, &pTransfer);
1976 if (RT_SUCCESS(rc))
1977 {
1978 /* Set the callbacks the (OS-dependent) implementation relies on. Optional. */
1979 ShClTransferSetCallbacks(pTransfer, &pCmdCtx->Transfers.Callbacks);
1980
1981 rc = ShClTransferCtxRegisterById(pTransferCtx, pTransfer, idTransfer);
1982 if ( RT_SUCCESS(rc)
1983 && ppTransfer)
1984 *ppTransfer = pTransfer;
1985 }
1986
1987 if (RT_SUCCESS(rc))
1988 LogRel(("Shared Clipboard: Transfer %RU32 successfully created\n", idTransfer));
1989 else
1990 LogRel(("Shared Clipboard: Error creating transfer %RU32, rc=%Rrc\n", idTransfer, rc));
1991
1992 LogFlowFuncLeaveRC(rc);
1993 return rc;
1994}
1995
1996/**
1997 * Initializes a transfer on the guest side.
1998 *
1999 * @returns VBox status code.
2000 * @param pCmdCtx Command context to use.
2001 * @param pTransfer Transfer to init.
2002 */
2003static int vbglR3ClipboardTransferInit(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFER pTransfer)
2004{
2005 LogFlowFuncEnter();
2006
2007 SHCLTRANSFERDIR const enmDir = ShClTransferGetDir(pTransfer);
2008
2009 SHCLTXPROVIDER Provider;
2010 RT_ZERO(Provider);
2011
2012 /* Assign local provider first and overwrite interface methods below if needed. */
2013 ShClTransferProviderLocalQueryInterface(&Provider);
2014
2015 /* If this is a read transfer (reading data from host), set the interface to use
2016 * our VbglR3 routines here. */
2017 if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE) /* Host -> Guest */
2018 {
2019 Provider.Interface.pfnRootListRead = vbglR3ClipboardTransferIfaceRootListRead;
2020
2021 Provider.Interface.pfnListOpen = vbglR3ClipboardTransferIfaceListOpen;
2022 Provider.Interface.pfnListClose = vbglR3ClipboardTransferIfaceListClose;
2023 Provider.Interface.pfnListHdrRead = vbglR3ClipboardTransferIfaceListHdrRead;
2024 Provider.Interface.pfnListEntryRead = vbglR3ClipboardTransferIfaceListEntryRead;
2025
2026 Provider.Interface.pfnObjOpen = vbglR3ClipboardTransferIfaceObjOpen;
2027 Provider.Interface.pfnObjClose = vbglR3ClipboardTransferIfaceObjClose;
2028 Provider.Interface.pfnObjRead = vbglR3ClipboardTransferIfaceObjRead;
2029 }
2030 else if (enmDir == SHCLTRANSFERDIR_TO_REMOTE) /* Guest -> Host */
2031 {
2032 /* Uses the local provider assigned above. */
2033 }
2034 else
2035 AssertFailed();
2036
2037 Provider.pvUser = pCmdCtx;
2038
2039 /* Set the provider first before calling ShClTransferInit(), as the init callback might utilize some of the
2040 * provider functions. */
2041 int rc = ShClTransferSetProvider(pTransfer, &Provider);
2042 if (RT_SUCCESS(rc))
2043 {
2044 rc = ShClTransferInit(pTransfer);
2045 if (RT_SUCCESS(rc))
2046 {
2047 /* As soon as we report the INITIALIZED state to the host, the host can start reading stuff from the transfer.
2048 * So make sure that we really are ready here. */
2049 if (enmDir == SHCLTRANSFERDIR_TO_REMOTE)
2050 AssertMsgStmt(ShClTransferRootsCount(pTransfer), ("No root entries set yet!\n"
2051 "Those have to be present as soon we report the transfer as being INITIALIZED to the host\n"),
2052 rc = VERR_WRONG_ORDER);
2053 }
2054 }
2055
2056 SHCLTRANSFERID const idTransfer = ShClTransferGetID(pTransfer);
2057
2058 if (RT_SUCCESS(rc))
2059 {
2060 LogRel(("Shared Clipboard: Transfer %RU32 (%s) successfully initialized\n",
2061 idTransfer, enmDir == SHCLTRANSFERDIR_FROM_REMOTE ? "host -> guest" : "guest -> host"));
2062 }
2063 else
2064 LogRel(("Shared Clipboard: Unable to initialize transfer %RU32, rc=%Rrc\n", idTransfer, rc));
2065
2066 LogFlowFuncLeaveRC(rc);
2067 return rc;
2068}
2069
2070/**
2071 * Destroys a transfer on the guest side.
2072 *
2073 * @returns VBox status code.
2074 * @param pCmdCtx Command context to use.
2075 * @param pTransferCtx Transfer context to uninit transfer for.
2076 * @param idTransfer ID of transfer to initialize.
2077 */
2078static int vbglR3ClipboardTransferDestroy(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx, SHCLTRANSFERID idTransfer)
2079{
2080 RT_NOREF(pCmdCtx);
2081
2082 LogFlowFuncEnter();
2083
2084 int rc;
2085
2086 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx, idTransfer);
2087 if (pTransfer)
2088 {
2089 rc = ShClTransferCtxUnregisterById(pTransferCtx, idTransfer);
2090 if (RT_SUCCESS(rc))
2091 rc = ShClTransferDestroy(pTransfer);
2092
2093 if (RT_SUCCESS(rc))
2094 {
2095 LogRel(("Shared Clipboard: Transfer %RU32 successfully uninitialized\n", idTransfer));
2096 }
2097 else
2098 LogRel(("Shared Clipboard: Unable to uninitialized transfer %RU32, rc=%Rrc\n", idTransfer, rc));
2099 }
2100 else
2101 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
2102
2103 /* Send a reply in any case. */
2104 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
2105 RT_SUCCESS(rc)
2106 ? SHCLTRANSFERSTATUS_UNINITIALIZED : SHCLTRANSFERSTATUS_ERROR, rc);
2107
2108 /* The host might not have the transfer around anymore at this time, so simply ignore this error. */
2109 if (rc2 == VERR_SHCLPB_TRANSFER_ID_NOT_FOUND)
2110 rc2 = VINF_SUCCESS;
2111
2112 if (RT_SUCCESS(rc))
2113 rc = rc2;
2114
2115 LogFlowFuncLeaveRC(rc);
2116 return rc;
2117}
2118
2119/**
2120 * Requests a new transfer from the host.
2121 *
2122 * On success this will issue an INITIALIZED status reply from the host with a transfer ID set.
2123 * This ID will be used to initialize the transfer on the guest side then.
2124 *
2125 * @returns VBox status code.
2126 * @param pCmdCtx Command context to use.
2127 */
2128VBGLR3DECL(int) VbglR3ClipboardTransferRequest(PVBGLR3SHCLCMDCTX pCmdCtx)
2129{
2130 LogFlowFuncEnter();
2131
2132 LogRel2(("Shared Clipboard: Requesting new host -> guest transfer from host\n"));
2133
2134 int rc = vbglR3ClipboardTransferStatusReplyEx(pCmdCtx, 0 /* Context ID not needed */,
2135 SHCLTRANSFERSTATUS_REQUESTED, VINF_SUCCESS);
2136 LogFlowFuncLeaveRC(rc);
2137 return rc;
2138}
2139
2140/**
2141 * Starts a transfer on the guest side.
2142 *
2143 * @returns VBox status code.
2144 * @param pCmdCtx Command context to use.
2145 * @param pTransferCtx Transfer context to start transfer for.
2146 * @param uTransferID ID to use for transfer to start.
2147 */
2148static int vbglR3ClipboardTransferStart(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
2149 SHCLTRANSFERID uTransferID)
2150{
2151 RT_NOREF(pCmdCtx);
2152
2153 LogFlowFuncEnter();
2154
2155 int rc;
2156
2157 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx, uTransferID);
2158 if (pTransfer)
2159 {
2160 rc = ShClTransferStart(pTransfer);
2161 if (RT_SUCCESS(rc))
2162 {
2163 LogRel(("Shared Clipboard: Transfer %RU32 successfully started\n", uTransferID));
2164 }
2165 else
2166 LogRel(("Shared Clipboard: Unable to start transfer %RU32, rc=%Rrc\n", uTransferID, rc));
2167 }
2168 else
2169 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
2170
2171 /* Send a reply in any case. */
2172 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
2173 RT_SUCCESS(rc)
2174 ? SHCLTRANSFERSTATUS_STARTED : SHCLTRANSFERSTATUS_ERROR, rc);
2175 if (RT_SUCCESS(rc))
2176 rc = rc2;
2177
2178 LogFlowFuncLeaveRC(rc);
2179 return rc;
2180}
2181
2182/**
2183 * Stops a transfer on the guest side.
2184 *
2185 * @returns VBox status code, or VERR_NOT_FOUND if transfer has not been found.
2186 * @param pCmdCtx Command context to use.
2187 * @param pTransferCtx Transfer context to stop transfer for.
2188 * @param uTransferID ID of transfer to stop.
2189 */
2190static int vbglR3ClipboardTransferStop(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
2191 SHCLTRANSFERID uTransferID)
2192{
2193 LogFlowFuncEnter();
2194
2195 int rc;
2196
2197 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx, uTransferID);
2198 if (pTransfer)
2199 {
2200 rc = ShClTransferCtxUnregisterById(pTransferCtx, uTransferID);
2201 if (RT_SUCCESS(rc))
2202 {
2203 LogRel(("Shared Clipboard: Transfer %RU32 successfully stopped\n", uTransferID));
2204 }
2205 else
2206 LogRel(("Shared Clipboard: Unable to stop transfer %RU32, rc=%Rrc\n", uTransferID, rc));
2207 }
2208 else
2209 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
2210
2211 /* Send a reply in any case. */
2212 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
2213 RT_SUCCESS(rc)
2214 ? SHCLTRANSFERSTATUS_STOPPED : SHCLTRANSFERSTATUS_ERROR, rc);
2215 if (RT_SUCCESS(rc))
2216 rc = rc2;
2217
2218 LogFlowFuncLeaveRC(rc);
2219 return rc;
2220}
2221
2222/**
2223 * Sets transfer callbacks of a Shared Clipboard command context.
2224 *
2225 * @param pCmdCtx Command context to set callbacks for.
2226 * @param pCallbacks Pointer to callback table to set.
2227 */
2228VBGLR3DECL(void) VbglR3ClipboardTransferSetCallbacks(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCALLBACKS pCallbacks)
2229{
2230 AssertPtrReturnVoid(pCmdCtx);
2231 AssertPtrReturnVoid(pCallbacks);
2232
2233 ShClTransferCopyCallbacks(&pCmdCtx->Transfers.Callbacks, pCallbacks);
2234}
2235
2236VBGLR3DECL(int) VbglR3ClipboardEventGetNextEx(uint32_t idMsg, uint32_t cParms,
2237 PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
2238 PVBGLR3CLIPBOARDEVENT pEvent)
2239{
2240 AssertPtrReturn(pCmdCtx, VERR_INVALID_POINTER);
2241 AssertPtrReturn(pTransferCtx, VERR_INVALID_POINTER);
2242 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
2243
2244 LogFunc(("Handling idMsg=%RU32 (%s), cParms=%RU32\n", idMsg, ShClHostMsgToStr(idMsg), cParms));
2245
2246 int rc;
2247 if (!pCmdCtx->fUseLegacyProtocol)
2248 {
2249 bool fErrorSent = false; /* Whether an error has been reported back to the host already. */
2250
2251 switch (idMsg)
2252 {
2253 case VBOX_SHCL_HOST_MSG_TRANSFER_STATUS:
2254 {
2255 SHCLTRANSFERDIR enmDir;
2256 SHCLTRANSFERREPORT transferReport;
2257 rc = VbglR3ClipboarTransferStatusRecv(pCmdCtx, &enmDir, &transferReport);
2258 if (RT_SUCCESS(rc))
2259 {
2260 const SHCLTRANSFERID idTransfer = VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext);
2261
2262 LogRel(("Shared Clipboard: Received status %s (%Rrc) for transfer %RU32\n",
2263 ShClTransferStatusToStr(transferReport.uStatus), transferReport.rc, idTransfer));
2264
2265 SHCLSOURCE enmSource = SHCLSOURCE_INVALID;
2266
2267 switch (transferReport.uStatus)
2268 {
2269 case SHCLTRANSFERSTATUS_REQUESTED: /* Only used for H->G transfers. */
2270 {
2271 enmDir = SHCLTRANSFERDIR_FROM_REMOTE;
2272 enmSource = SHCLSOURCE_REMOTE;
2273
2274 /* The host acknowledged our request to create a new transfer.
2275 * So create a new transfer here with the transfer ID we just got from the host.
2276 *
2277 * Actual initialization will be done as soon as the host sends use the INITIALIZED status for it.
2278 */
2279 PSHCLTRANSFER pTransfer;
2280 rc = vbglR3ClipboardTransferCreate(pCmdCtx, pTransferCtx, enmDir, enmSource, idTransfer, &pTransfer);
2281
2282 /* As soon as we've created our transfer locally, report back INITIALIZED to the host.
2283 * This will initialize the transfer on the host, so that in turn reports INITIALIZED
2284 * back to us (see case down below).*/
2285 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
2286 RT_SUCCESS(rc)
2287 ? SHCLTRANSFERSTATUS_INITIALIZED : SHCLTRANSFERSTATUS_ERROR, rc);
2288 if (RT_SUCCESS(rc))
2289 rc = rc2;
2290 break;
2291 }
2292
2293 case SHCLTRANSFERSTATUS_INITIALIZED:
2294 {
2295 /* The host announces the transfer direction from its point of view, so inverse the direction here. */
2296 if (enmDir == SHCLTRANSFERDIR_TO_REMOTE) /* H -> G */
2297 {
2298 enmDir = SHCLTRANSFERDIR_FROM_REMOTE;
2299 enmSource = SHCLSOURCE_REMOTE;
2300 }
2301 else if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE) /* G -> H */
2302 {
2303 enmDir = SHCLTRANSFERDIR_TO_REMOTE;
2304 enmSource = SHCLSOURCE_LOCAL;
2305 }
2306 else
2307 AssertFailedBreakStmt(rc = VERR_INVALID_PARAMETER);
2308
2309 if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE) /* H->G */
2310 {
2311 /* The host reported INITIALIZED for the transfer.
2312 * So init our local transfer as well now. */
2313 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx, idTransfer);
2314 if (pTransfer)
2315 {
2316 rc = vbglR3ClipboardTransferInit(pCmdCtx, pTransfer);
2317
2318 /* Only send back a reply on error -- we already reported INITIALIZED
2319 * in the case SHCLTRANSFERSTATUS_REQUESTED above. */
2320 if (RT_FAILURE(rc))
2321 {
2322 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
2323 SHCLTRANSFERSTATUS_ERROR, rc);
2324 AssertRC(rc2);
2325 }
2326 }
2327 else
2328 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
2329 }
2330 else if (enmDir == SHCLTRANSFERDIR_TO_REMOTE) /* G->H */
2331 {
2332 /* The host reported the INITIALIZED status together with the transfer ID.
2333 * So create a local transfer here with that ID. */
2334 PSHCLTRANSFER pTransfer;
2335 rc = vbglR3ClipboardTransferCreate(pCmdCtx, pTransferCtx, enmDir, enmSource, idTransfer, &pTransfer);
2336 if (RT_SUCCESS(rc))
2337 rc = vbglR3ClipboardTransferInit(pCmdCtx, pTransfer);
2338
2339 /* Send a reply in any case. */
2340 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
2341 RT_SUCCESS(rc)
2342 ? SHCLTRANSFERSTATUS_INITIALIZED : SHCLTRANSFERSTATUS_ERROR, rc);
2343 if (RT_SUCCESS(rc))
2344 rc = rc2;
2345 }
2346 else
2347 AssertFailedBreakStmt(rc = VERR_INVALID_PARAMETER);
2348
2349 break;
2350 }
2351
2352 case SHCLTRANSFERSTATUS_UNINITIALIZED:
2353 {
2354 rc = vbglR3ClipboardTransferDestroy(pCmdCtx, pTransferCtx, idTransfer);
2355 break;
2356 }
2357
2358 case SHCLTRANSFERSTATUS_STARTED:
2359 {
2360 rc = vbglR3ClipboardTransferStart(pCmdCtx, pTransferCtx, idTransfer);
2361 break;
2362 }
2363
2364 case SHCLTRANSFERSTATUS_STOPPED:
2365 RT_FALL_THROUGH();
2366 case SHCLTRANSFERSTATUS_CANCELED:
2367 RT_FALL_THROUGH();
2368 case SHCLTRANSFERSTATUS_KILLED:
2369 RT_FALL_THROUGH();
2370 case SHCLTRANSFERSTATUS_ERROR:
2371 {
2372 rc = vbglR3ClipboardTransferStop(pCmdCtx, pTransferCtx, idTransfer);
2373 break;
2374 }
2375
2376 default:
2377 LogRel(("Shared Clipboard: Received unknown status %#x (%Rrc) for transfer %RU32\n",
2378 transferReport.uStatus, pEvent->u.TransferStatus.Report.rc, pEvent->u.TransferStatus.uID));
2379 rc = VERR_NOT_SUPPORTED;
2380 break;
2381 }
2382
2383 if (RT_SUCCESS(rc))
2384 {
2385 pEvent->u.TransferStatus.enmDir = enmDir;
2386 pEvent->u.TransferStatus.Report = transferReport;
2387 pEvent->u.TransferStatus.uID = VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext);
2388
2389 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_TRANSFER_STATUS;
2390 }
2391 }
2392 break;
2393 }
2394
2395 case VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ:
2396 {
2397 uint32_t fRoots;
2398 rc = VbglR3ClipboardTransferRootListHdrReadReq(pCmdCtx, &fRoots);
2399
2400 /** @todo Validate / handle fRoots. */
2401
2402 if (RT_SUCCESS(rc))
2403 {
2404 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2405 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2406 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2407
2408 SHCLLISTHDR rootListHdr;
2409 ShClTransferListHdrInit(&rootListHdr);
2410
2411 rootListHdr.cEntries = ShClTransferRootsCount(pTransfer);
2412
2413 LogFlowFunc(("cRoots=%RU32\n", rootListHdr.cEntries));
2414
2415 rc = VbglR3ClipboardTransferRootListHdrReadReply(pCmdCtx, &rootListHdr);
2416 }
2417 break;
2418 }
2419
2420 case VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ:
2421 {
2422 uint64_t uIndex;
2423 uint32_t fInfo;
2424 rc = VbglR3ClipboardTransferRootListEntryReadReq(pCmdCtx, &uIndex, &fInfo);
2425 if (RT_SUCCESS(rc))
2426 {
2427 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2428 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2429 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2430
2431 PCSHCLLISTENTRY pEntry = ShClTransferRootsEntryGet(pTransfer, uIndex);
2432 if (pEntry)
2433 {
2434 rc = VbglR3ClipboardTransferRootListEntryReadReply(pCmdCtx, uIndex, pEntry);
2435 }
2436 else
2437 rc = VERR_NOT_FOUND;
2438 }
2439 break;
2440 }
2441
2442 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN:
2443 {
2444 SHCLLISTOPENPARMS openParmsList;
2445 rc = ShClTransferListOpenParmsInit(&openParmsList);
2446 if (RT_SUCCESS(rc))
2447 {
2448 rc = VbglR3ClipboardTransferListOpenRecv(pCmdCtx, &openParmsList);
2449 if (RT_SUCCESS(rc))
2450 {
2451 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2452 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2453 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2454
2455 LogFlowFunc(("pszPath=%s\n", openParmsList.pszPath));
2456
2457 SHCLLISTHANDLE hList = NIL_SHCLLISTHANDLE;
2458 rc = ShClTransferListOpen(pTransfer, &openParmsList, &hList);
2459
2460 /* Reply in any case. */
2461 int rc2 = VbglR3ClipboardTransferListOpenReply(pCmdCtx, rc, hList);
2462 AssertRC(rc2);
2463 }
2464
2465 ShClTransferListOpenParmsDestroy(&openParmsList);
2466 }
2467
2468 break;
2469 }
2470
2471 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE:
2472 {
2473 SHCLLISTHANDLE hList;
2474 rc = VbglR3ClipboardTransferListCloseRecv(pCmdCtx, &hList);
2475 if (RT_SUCCESS(rc))
2476 {
2477 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2478 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2479 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2480
2481 rc = ShClTransferListClose(pTransfer, hList);
2482
2483 /* Reply in any case. */
2484 int rc2 = VbglR3ClipboardTransferListCloseReply(pCmdCtx, rc, hList);
2485 AssertRC(rc2);
2486 }
2487
2488 break;
2489 }
2490
2491 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ:
2492 {
2493 /** @todo Handle filter + list features. */
2494
2495 SHCLLISTHANDLE hList = NIL_SHCLLISTHANDLE;
2496 uint32_t fFlags = 0;
2497 rc = VbglR3ClipboardTransferListHdrReadRecvReq(pCmdCtx, &hList, &fFlags);
2498 if (RT_SUCCESS(rc))
2499 {
2500 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2501 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2502 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2503
2504 SHCLLISTHDR hdrList;
2505 rc = ShClTransferListGetHeader(pTransfer, hList, &hdrList);
2506 if (RT_SUCCESS(rc))
2507 {
2508 rc = VbglR3ClipboardTransferListHdrWrite(pCmdCtx, hList, &hdrList);
2509
2510 ShClTransferListHdrDestroy(&hdrList);
2511 }
2512 }
2513
2514 break;
2515 }
2516
2517 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ:
2518 {
2519 LogFlowFunc(("VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ\n"));
2520
2521 SHCLLISTENTRY entryList;
2522 rc = ShClTransferListEntryInit(&entryList);
2523 if (RT_SUCCESS(rc))
2524 {
2525 SHCLLISTHANDLE hList;
2526 uint32_t fInfo;
2527 rc = VbglR3ClipboardTransferListEntryReadRecvReq(pCmdCtx, &hList, &fInfo);
2528 if (RT_SUCCESS(rc))
2529 {
2530 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2531 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2532 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2533
2534 rc = ShClTransferListRead(pTransfer, hList, &entryList);
2535 if (RT_SUCCESS(rc))
2536 {
2537 PSHCLFSOBJINFO pObjInfo = (PSHCLFSOBJINFO)entryList.pvInfo;
2538 Assert(entryList.cbInfo == sizeof(SHCLFSOBJINFO));
2539
2540 RT_NOREF(pObjInfo);
2541
2542 LogFlowFunc(("\t%s (%RU64 bytes)\n", entryList.pszName, pObjInfo->cbObject));
2543
2544 rc = VbglR3ClipboardTransferListEntryWrite(pCmdCtx, hList, &entryList);
2545 }
2546 }
2547
2548 ShClTransferListEntryDestroy(&entryList);
2549 }
2550
2551 break;
2552 }
2553
2554 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN:
2555 {
2556 SHCLOBJOPENCREATEPARMS openParms;
2557 rc = ShClTransferObjOpenParmsInit(&openParms);
2558 if (RT_SUCCESS(rc))
2559 {
2560 rc = VbglR3ClipboardTransferObjOpenRecv(pCmdCtx, &openParms);
2561 if (RT_SUCCESS(rc))
2562 {
2563 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2564 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2565 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2566
2567 SHCLOBJHANDLE hObj;
2568 rc = ShClTransferObjOpen(pTransfer, &openParms, &hObj);
2569
2570 /* Reply in any case. */
2571 int rc2 = VbglR3ClipboardTransferObjOpenReply(pCmdCtx, rc, hObj);
2572 AssertRC(rc2);
2573 }
2574
2575 ShClTransferObjOpenParmsDestroy(&openParms);
2576 }
2577
2578 break;
2579 }
2580
2581 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE:
2582 {
2583 SHCLOBJHANDLE hObj;
2584 rc = VbglR3ClipboardTransferObjCloseRecv(pCmdCtx, &hObj);
2585 if (RT_SUCCESS(rc))
2586 {
2587 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2588 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2589 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2590
2591 rc = ShClTransferObjClose(pTransfer, hObj);
2592
2593 /* Reply in any case. */
2594 int rc2 = VbglR3ClipboardTransferObjCloseReply(pCmdCtx, rc, hObj);
2595 AssertRC(rc2);
2596 }
2597
2598 break;
2599 }
2600
2601 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ:
2602 {
2603 SHCLOBJHANDLE hObj;
2604 uint32_t cbBuf;
2605 uint32_t fFlags;
2606 rc = VbglR3ClipboardTransferObjReadRecv(pCmdCtx, &hObj, &cbBuf, &fFlags);
2607 if (RT_SUCCESS(rc))
2608 {
2609 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2610 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2611 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2612
2613 AssertBreakStmt(pCmdCtx->Transfers.cbChunkSize, rc = VERR_INVALID_PARAMETER);
2614
2615 const uint32_t cbToRead = RT_MIN(cbBuf, pCmdCtx->Transfers.cbChunkSize);
2616
2617 LogFlowFunc(("hObj=%RU64, cbBuf=%RU32, fFlags=0x%x -> cbChunkSize=%RU32, cbToRead=%RU32\n",
2618 hObj, cbBuf, fFlags, pCmdCtx->Transfers.cbChunkSize, cbToRead));
2619
2620 void *pvBuf = RTMemAlloc(cbToRead);
2621 if (pvBuf)
2622 {
2623 uint32_t cbRead;
2624 rc = ShClTransferObjRead(pTransfer, hObj, pvBuf, cbToRead, fFlags, &cbRead);
2625 if (RT_SUCCESS(rc))
2626 rc = VbglR3ClipboardTransferObjWriteSend(pCmdCtx, hObj, pvBuf, cbRead, NULL /* pcbWritten */);
2627
2628 RTMemFree(pvBuf);
2629 }
2630 else
2631 rc = VERR_NO_MEMORY;
2632 }
2633
2634 break;
2635 }
2636
2637 default:
2638 {
2639 rc = VbglR3ClipboardEventGetNext(idMsg, cParms, pCmdCtx, pEvent);
2640 if (RT_FAILURE(rc))
2641 fErrorSent = true;
2642 break;
2643 }
2644 }
2645
2646 if ( !fErrorSent
2647 && RT_FAILURE(rc))
2648 {
2649 /* Report error back to the host. */
2650 int rc2 = VbglR3ClipboardWriteError(pCmdCtx->idClient, rc);
2651 AssertRC(rc2);
2652 }
2653 }
2654 else
2655 {
2656 /*
2657 * This builds on what we did in VbglR3ClipboardMsgPeekWait, so
2658 * !HACK ALERT! cParms is the format flag or flags.
2659 */
2660 rc = VINF_SUCCESS;
2661 switch (idMsg)
2662 {
2663 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
2664 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
2665 pEvent->u.fReportedFormats = cParms;
2666 break;
2667
2668 case VBOX_SHCL_HOST_MSG_READ_DATA:
2669 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2670 pEvent->u.fReadData = cParms;
2671 break;
2672
2673 case VBOX_SHCL_HOST_MSG_QUIT:
2674 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
2675 break;
2676
2677 default:
2678 AssertMsgFailed(("%u (%#x)\n", idMsg, idMsg));
2679 rc = VERR_NOT_SUPPORTED;
2680 break;
2681 }
2682 }
2683
2684 LogFlowFuncLeaveRC(rc);
2685 return rc;
2686}
2687
2688#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
2689
2690VBGLR3DECL(int) VbglR3ClipboardEventGetNext(uint32_t idMsg, uint32_t cParms, PVBGLR3SHCLCMDCTX pCtx, PVBGLR3CLIPBOARDEVENT pEvent)
2691{
2692 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
2693 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
2694
2695 RT_NOREF(cParms);
2696
2697 int rc;
2698 if (!pCtx->fUseLegacyProtocol)
2699 {
2700 LogFunc(("Handling idMsg=%RU32 (%s)\n", idMsg, ShClHostMsgToStr(idMsg)));
2701 switch (idMsg)
2702 {
2703 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
2704 {
2705 rc = vbglR3ClipboardFormatsReportRecv(pCtx, &pEvent->u.fReportedFormats);
2706 if (RT_SUCCESS(rc))
2707 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
2708 break;
2709 }
2710
2711 case VBOX_SHCL_HOST_MSG_READ_DATA_CID:
2712 {
2713 rc = vbglR3ClipboardFetchReadDataCid(pCtx, &pEvent->u.fReadData);
2714 if (RT_SUCCESS(rc))
2715 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2716 break;
2717 }
2718
2719 case VBOX_SHCL_HOST_MSG_READ_DATA:
2720 {
2721 rc = vbglR3ClipboardFetchReadData(pCtx, &pEvent->u.fReadData);
2722 if (RT_SUCCESS(rc))
2723 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2724 break;
2725 }
2726
2727 case VBOX_SHCL_HOST_MSG_QUIT:
2728 {
2729 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
2730 rc = VINF_SUCCESS;
2731 break;
2732 }
2733
2734 default:
2735 {
2736 /** @todo r=bird: BUGBUG - need a skip command here! */
2737 rc = VERR_NOT_SUPPORTED;
2738 break;
2739 }
2740 }
2741
2742 if (RT_SUCCESS(rc))
2743 {
2744 /* Copy over our command context to the event. */
2745 pEvent->cmdCtx = *pCtx;
2746 }
2747 else
2748 {
2749 /* Report error back to the host. */
2750 int rc2 = VbglR3ClipboardWriteError(pCtx->idClient, rc);
2751 AssertRC(rc2);
2752 }
2753 }
2754 else
2755 {
2756 /*
2757 * This builds on what we did in VbglR3ClipboardMsgPeekWait, so
2758 * !HACK ALERT! cParms is the format flag or flags.
2759 */
2760 rc = VINF_SUCCESS;
2761 switch (idMsg)
2762 {
2763 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
2764 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
2765 pEvent->u.fReportedFormats = cParms;
2766 break;
2767
2768 case VBOX_SHCL_HOST_MSG_READ_DATA:
2769 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2770 pEvent->u.fReadData = cParms;
2771 break;
2772
2773 case VBOX_SHCL_HOST_MSG_QUIT:
2774 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
2775 break;
2776
2777 default:
2778 AssertMsgFailed(("%u (%#x)\n", idMsg, idMsg));
2779 rc = VERR_NOT_SUPPORTED;
2780 break;
2781 }
2782 pEvent->cmdCtx = *pCtx;
2783 }
2784
2785 LogFlowFuncLeaveRC(rc);
2786 return rc;
2787}
2788
2789/**
2790 * Frees (destroys) a formerly allocated Shared Clipboard event.
2791 *
2792 * @returns IPRT status code.
2793 * @param pEvent Event to free (destroy).
2794 */
2795VBGLR3DECL(void) VbglR3ClipboardEventFree(PVBGLR3CLIPBOARDEVENT pEvent)
2796{
2797 if (!pEvent)
2798 return;
2799
2800 /* Some messages require additional cleanup. */
2801 switch (pEvent->enmType)
2802 {
2803 default:
2804 break;
2805 }
2806
2807 RTMemFree(pEvent);
2808 pEvent = NULL;
2809}
2810
2811/**
2812 * Reports (advertises) guest clipboard formats to the host.
2813 *
2814 * Legacy function, do not use anymore.
2815 *
2816 * @returns VBox status code.
2817 * @param idClient The client id returned by VbglR3ClipboardConnect().
2818 * @param fFormats The formats to report.
2819 */
2820VBGLR3DECL(int) VbglR3ClipboardReportFormats(HGCMCLIENTID idClient, uint32_t fFormats)
2821{
2822 struct
2823 {
2824 VBGLIOCHGCMCALL Hdr;
2825 VBoxShClParmReportFormats Parms;
2826 } Msg;
2827
2828 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_REPORT_FORMATS, VBOX_SHCL_CPARMS_REPORT_FORMATS);
2829 VbglHGCMParmUInt32Set(&Msg.Parms.f32Formats, fFormats);
2830
2831 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
2832
2833 LogFlowFuncLeaveRC(rc);
2834 return rc;
2835}
2836
2837/**
2838 * Sends guest clipboard data to the host.
2839 *
2840 * Legacy function kept for compatibility, do not use anymore.
2841 *
2842 * This is usually called in reply to a VBOX_SHCL_HOST_MSG_READ_DATA message
2843 * from the host.
2844 *
2845 * @returns VBox status code.
2846 * @param idClient The client id returned by VbglR3ClipboardConnect().
2847 * @param fFormat The format of the data.
2848 * @param pvData Pointer to the data to send. Can be NULL if @a cbData
2849 * is zero.
2850 * @param cbData Number of bytes of data to send. Zero is valid.
2851 */
2852VBGLR3DECL(int) VbglR3ClipboardWriteData(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb)
2853{
2854 LogFlowFuncEnter();
2855
2856 struct
2857 {
2858 VBGLIOCHGCMCALL Hdr;
2859 VBoxShClParmDataWriteOld Parms;
2860 } Msg;
2861
2862 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_DATA_WRITE, VBOX_SHCL_CPARMS_DATA_WRITE_OLD);
2863 VbglHGCMParmUInt32Set(&Msg.Parms.f32Format, fFormat);
2864 VbglHGCMParmPtrSet(&Msg.Parms.pData, pv, cb);
2865
2866 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
2867
2868 LogFlowFuncLeaveRC(rc);
2869 return rc;
2870}
2871
2872/**
2873 * Sends guest clipboard data to the host.
2874 *
2875 * This is usually called in reply to a VBOX_SHCL_HOST_MSG_READ_DATA message
2876 * from the host.
2877 *
2878 * @returns VBox status code.
2879 * @param pCtx The command context returned by VbglR3ClipboardConnectEx().
2880 * @param fFormat Clipboard format to send.
2881 * @param pvData Pointer to the data to send. Can be NULL if @a cbData
2882 * is zero.
2883 * @param cbData Number of bytes of data to send. Zero is valid.
2884 */
2885VBGLR3DECL(int) VbglR3ClipboardWriteDataEx(PVBGLR3SHCLCMDCTX pCtx, SHCLFORMAT fFormat, void *pvData, uint32_t cbData)
2886{
2887 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
2888 AssertReturn(cbData == 0 || RT_VALID_PTR(pvData), VERR_INVALID_PARAMETER);
2889
2890 LogFlowFunc(("fFormat=%#x pvData=%p cbData=%#x\n", fFormat, pvData, cbData));
2891
2892 int rc;
2893 if (pCtx->fUseLegacyProtocol)
2894 rc = VbglR3ClipboardWriteData(pCtx->idClient, fFormat, pvData, cbData);
2895 else
2896 {
2897 struct
2898 {
2899 VBGLIOCHGCMCALL Hdr;
2900 VBoxShClParmDataWrite Parms;
2901 } Msg;
2902
2903 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_DATA_WRITE, VBOX_SHCL_CPARMS_DATA_WRITE);
2904 Msg.Parms.id64Context.SetUInt64(pCtx->idContext);
2905 Msg.Parms.f32Format.SetUInt32(fFormat);
2906 Msg.Parms.pData.SetPtr(pvData, cbData);
2907
2908 LogFlowFunc(("CID=%RU32\n", pCtx->idContext));
2909
2910 rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
2911 }
2912
2913 LogFlowFuncLeaveRC(rc);
2914 return rc;
2915}
2916
2917/**
2918 * Writes an error to the host.
2919 *
2920 * @returns IPRT status code.
2921 * @param idClient The client id returned by VbglR3ClipboardConnect().
2922 * @param rcErr Error (IPRT-style) to send.
2923 */
2924VBGLR3DECL(int) VbglR3ClipboardWriteError(HGCMCLIENTID idClient, int rcErr)
2925{
2926 AssertReturn(idClient, VERR_INVALID_PARAMETER);
2927
2928 VBoxShClWriteErrorMsg Msg;
2929 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHCL_GUEST_FN_ERROR, VBOX_SHCL_CPARMS_ERROR);
2930
2931 /** @todo Context ID not used yet. */
2932 Msg.uContext.SetUInt64(0);
2933 Msg.rc.SetUInt32((uint32_t)rcErr); /* uint32_t vs. int. */
2934
2935 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
2936
2937 if (RT_FAILURE(rc))
2938 LogFlowFunc(("Sending error %Rrc failed with rc=%Rrc\n", rcErr, rc));
2939 if (rc == VERR_NOT_SUPPORTED)
2940 rc = VINF_SUCCESS;
2941
2942 if (RT_FAILURE(rc))
2943 LogRel(("Shared Clipboard: Reporting error %Rrc to the host failed with %Rrc\n", rcErr, rc));
2944
2945 LogFlowFuncLeaveRC(rc);
2946 return rc;
2947}
2948
Note: See TracBrowser for help on using the repository browser.

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