VirtualBox

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

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

Shared Clipboard: Made setting the transfer callbacks part of ShClTransferCreate(), otherwise the pfnOnCreated callback won't be called. ​​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: 105.5 KB
Line 
1/* $Id: VBoxGuestR3LibClipboard.cpp 100393 2023-07-05 16:18:02Z 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 RT_NOREF(pTransfer); /* Currently not used (yet). */
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, &pCmdCtx->Transfers.Callbacks, &pTransfer);
1976 if (RT_SUCCESS(rc))
1977 {
1978 rc = ShClTransferCtxRegisterById(pTransferCtx, pTransfer, idTransfer);
1979 if ( RT_SUCCESS(rc)
1980 && ppTransfer)
1981 *ppTransfer = pTransfer;
1982 }
1983
1984 if (RT_SUCCESS(rc))
1985 LogRel(("Shared Clipboard: Transfer %RU32 successfully created\n", idTransfer));
1986 else
1987 LogRel(("Shared Clipboard: Error creating transfer %RU32, rc=%Rrc\n", idTransfer, rc));
1988
1989 LogFlowFuncLeaveRC(rc);
1990 return rc;
1991}
1992
1993/**
1994 * Initializes a transfer on the guest side.
1995 *
1996 * @returns VBox status code.
1997 * @param pCmdCtx Command context to use.
1998 * @param pTransfer Transfer to init.
1999 */
2000static int vbglR3ClipboardTransferInit(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFER pTransfer)
2001{
2002 LogFlowFuncEnter();
2003
2004 SHCLTRANSFERDIR const enmDir = ShClTransferGetDir(pTransfer);
2005
2006 SHCLTXPROVIDER Provider;
2007 RT_ZERO(Provider);
2008
2009 /* Assign local provider first and overwrite interface methods below if needed. */
2010 ShClTransferProviderLocalQueryInterface(&Provider);
2011
2012 /* If this is a read transfer (reading data from host), set the interface to use
2013 * our VbglR3 routines here. */
2014 if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE) /* Host -> Guest */
2015 {
2016 Provider.Interface.pfnRootListRead = vbglR3ClipboardTransferIfaceRootListRead;
2017
2018 Provider.Interface.pfnListOpen = vbglR3ClipboardTransferIfaceListOpen;
2019 Provider.Interface.pfnListClose = vbglR3ClipboardTransferIfaceListClose;
2020 Provider.Interface.pfnListHdrRead = vbglR3ClipboardTransferIfaceListHdrRead;
2021 Provider.Interface.pfnListEntryRead = vbglR3ClipboardTransferIfaceListEntryRead;
2022
2023 Provider.Interface.pfnObjOpen = vbglR3ClipboardTransferIfaceObjOpen;
2024 Provider.Interface.pfnObjClose = vbglR3ClipboardTransferIfaceObjClose;
2025 Provider.Interface.pfnObjRead = vbglR3ClipboardTransferIfaceObjRead;
2026 }
2027 else if (enmDir == SHCLTRANSFERDIR_TO_REMOTE) /* Guest -> Host */
2028 {
2029 /* Uses the local provider assigned above. */
2030 }
2031 else
2032 AssertFailed();
2033
2034 Provider.pvUser = pCmdCtx;
2035
2036 /* Set the provider first before calling ShClTransferInit(), as the init callback might utilize some of the
2037 * provider functions. */
2038 int rc = ShClTransferSetProvider(pTransfer, &Provider);
2039 if (RT_SUCCESS(rc))
2040 {
2041 rc = ShClTransferInit(pTransfer);
2042 if (RT_SUCCESS(rc))
2043 {
2044 /* As soon as we report the INITIALIZED state to the host, the host can start reading stuff from the transfer.
2045 * So make sure that we really are ready here. */
2046 if (enmDir == SHCLTRANSFERDIR_TO_REMOTE)
2047 AssertMsgStmt(ShClTransferRootsCount(pTransfer), ("No root entries set yet!\n"
2048 "Those have to be present as soon we report the transfer as being INITIALIZED to the host\n"),
2049 rc = VERR_WRONG_ORDER);
2050 }
2051 }
2052
2053 SHCLTRANSFERID const idTransfer = ShClTransferGetID(pTransfer);
2054
2055 if (RT_SUCCESS(rc))
2056 {
2057 LogRel(("Shared Clipboard: Transfer %RU32 (%s) successfully initialized\n",
2058 idTransfer, enmDir == SHCLTRANSFERDIR_FROM_REMOTE ? "host -> guest" : "guest -> host"));
2059 }
2060 else
2061 LogRel(("Shared Clipboard: Unable to initialize transfer %RU32, rc=%Rrc\n", idTransfer, rc));
2062
2063 LogFlowFuncLeaveRC(rc);
2064 return rc;
2065}
2066
2067/**
2068 * Destroys a transfer on the guest side.
2069 *
2070 * @returns VBox status code.
2071 * @param pCmdCtx Command context to use.
2072 * @param pTransferCtx Transfer context to uninit transfer for.
2073 * @param idTransfer ID of transfer to initialize.
2074 */
2075static int vbglR3ClipboardTransferDestroy(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx, SHCLTRANSFERID idTransfer)
2076{
2077 RT_NOREF(pCmdCtx);
2078
2079 LogFlowFuncEnter();
2080
2081 int rc;
2082
2083 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx, idTransfer);
2084 if (pTransfer)
2085 {
2086 rc = ShClTransferCtxUnregisterById(pTransferCtx, idTransfer);
2087 if (RT_SUCCESS(rc))
2088 rc = ShClTransferDestroy(pTransfer);
2089
2090 if (RT_SUCCESS(rc))
2091 {
2092 LogRel(("Shared Clipboard: Transfer %RU32 successfully uninitialized\n", idTransfer));
2093 }
2094 else
2095 LogRel(("Shared Clipboard: Unable to uninitialized transfer %RU32, rc=%Rrc\n", idTransfer, rc));
2096 }
2097 else
2098 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
2099
2100 /* Send a reply in any case. */
2101 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
2102 RT_SUCCESS(rc)
2103 ? SHCLTRANSFERSTATUS_UNINITIALIZED : SHCLTRANSFERSTATUS_ERROR, rc);
2104
2105 /* The host might not have the transfer around anymore at this time, so simply ignore this error. */
2106 if (rc2 == VERR_SHCLPB_TRANSFER_ID_NOT_FOUND)
2107 rc2 = VINF_SUCCESS;
2108
2109 if (RT_SUCCESS(rc))
2110 rc = rc2;
2111
2112 LogFlowFuncLeaveRC(rc);
2113 return rc;
2114}
2115
2116/**
2117 * Requests a new host -> guest transfer from the host.
2118 *
2119 * On success this will issue an INITIALIZED status reply from the host with a transfer ID set.
2120 * This ID will be used to initialize the transfer on the guest side then.
2121 *
2122 * @returns VBox status code.
2123 * @param pCmdCtx Command context to use.
2124 */
2125VBGLR3DECL(int) VbglR3ClipboardTransferRequest(PVBGLR3SHCLCMDCTX pCmdCtx)
2126{
2127 LogFlowFuncEnter();
2128
2129 LogRel2(("Shared Clipboard: Requesting new host -> guest transfer from host\n"));
2130
2131 int rc = vbglR3ClipboardTransferStatusReplyEx(pCmdCtx, 0 /* Context ID not needed */,
2132 SHCLTRANSFERSTATUS_REQUESTED, VINF_SUCCESS);
2133 LogFlowFuncLeaveRC(rc);
2134 return rc;
2135}
2136
2137/**
2138 * Starts a transfer on the guest side.
2139 *
2140 * @returns VBox status code.
2141 * @param pCmdCtx Command context to use.
2142 * @param pTransferCtx Transfer context to start transfer for.
2143 * @param uTransferID ID to use for transfer to start.
2144 */
2145static int vbglR3ClipboardTransferStart(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
2146 SHCLTRANSFERID uTransferID)
2147{
2148 RT_NOREF(pCmdCtx);
2149
2150 LogFlowFuncEnter();
2151
2152 int rc;
2153
2154 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx, uTransferID);
2155 if (pTransfer)
2156 {
2157 rc = ShClTransferStart(pTransfer);
2158 if (RT_SUCCESS(rc))
2159 {
2160 LogRel(("Shared Clipboard: Transfer %RU32 successfully started\n", uTransferID));
2161 }
2162 else
2163 LogRel(("Shared Clipboard: Unable to start transfer %RU32, rc=%Rrc\n", uTransferID, rc));
2164 }
2165 else
2166 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
2167
2168 /* Send a reply in any case. */
2169 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
2170 RT_SUCCESS(rc)
2171 ? SHCLTRANSFERSTATUS_STARTED : SHCLTRANSFERSTATUS_ERROR, rc);
2172 if (RT_SUCCESS(rc))
2173 rc = rc2;
2174
2175 LogFlowFuncLeaveRC(rc);
2176 return rc;
2177}
2178
2179/**
2180 * Stops a transfer on the guest side.
2181 *
2182 * @returns VBox status code, or VERR_NOT_FOUND if transfer has not been found.
2183 * @param pCmdCtx Command context to use.
2184 * @param pTransferCtx Transfer context to stop transfer for.
2185 * @param uTransferID ID of transfer to stop.
2186 */
2187static int vbglR3ClipboardTransferStop(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
2188 SHCLTRANSFERID uTransferID)
2189{
2190 LogFlowFuncEnter();
2191
2192 int rc;
2193
2194 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx, uTransferID);
2195 if (pTransfer)
2196 {
2197 rc = ShClTransferCtxUnregisterById(pTransferCtx, uTransferID);
2198 if (RT_SUCCESS(rc))
2199 {
2200 LogRel(("Shared Clipboard: Transfer %RU32 successfully stopped\n", uTransferID));
2201 }
2202 else
2203 LogRel(("Shared Clipboard: Unable to stop transfer %RU32, rc=%Rrc\n", uTransferID, rc));
2204 }
2205 else
2206 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
2207
2208 /* Send a reply in any case. */
2209 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
2210 RT_SUCCESS(rc)
2211 ? SHCLTRANSFERSTATUS_STOPPED : SHCLTRANSFERSTATUS_ERROR, rc);
2212 if (RT_SUCCESS(rc))
2213 rc = rc2;
2214
2215 LogFlowFuncLeaveRC(rc);
2216 return rc;
2217}
2218
2219VBGLR3DECL(int) VbglR3ClipboardEventGetNextEx(uint32_t idMsg, uint32_t cParms,
2220 PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
2221 PVBGLR3CLIPBOARDEVENT pEvent)
2222{
2223 AssertPtrReturn(pCmdCtx, VERR_INVALID_POINTER);
2224 AssertPtrReturn(pTransferCtx, VERR_INVALID_POINTER);
2225 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
2226
2227 LogFunc(("Handling idMsg=%RU32 (%s), cParms=%RU32\n", idMsg, ShClHostMsgToStr(idMsg), cParms));
2228
2229 int rc;
2230 if (!pCmdCtx->fUseLegacyProtocol)
2231 {
2232 bool fErrorSent = false; /* Whether an error has been reported back to the host already. */
2233
2234 switch (idMsg)
2235 {
2236 case VBOX_SHCL_HOST_MSG_TRANSFER_STATUS:
2237 {
2238 SHCLTRANSFERDIR enmDir;
2239 SHCLTRANSFERREPORT transferReport;
2240 rc = VbglR3ClipboarTransferStatusRecv(pCmdCtx, &enmDir, &transferReport);
2241 if (RT_SUCCESS(rc))
2242 {
2243 const SHCLTRANSFERID idTransfer = VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext);
2244
2245 LogRel(("Shared Clipboard: Received status %s (%Rrc) for transfer %RU32\n",
2246 ShClTransferStatusToStr(transferReport.uStatus), transferReport.rc, idTransfer));
2247
2248 SHCLSOURCE enmSource = SHCLSOURCE_INVALID;
2249
2250 switch (transferReport.uStatus)
2251 {
2252 case SHCLTRANSFERSTATUS_REQUESTED: /* Only used for H->G transfers. */
2253 {
2254 enmDir = SHCLTRANSFERDIR_FROM_REMOTE;
2255 enmSource = SHCLSOURCE_REMOTE;
2256
2257 /* The host acknowledged our request to create a new transfer.
2258 * So create a new transfer here with the transfer ID we just got from the host.
2259 *
2260 * Actual initialization will be done as soon as the host sends use the INITIALIZED status for it.
2261 */
2262 PSHCLTRANSFER pTransfer;
2263 rc = vbglR3ClipboardTransferCreate(pCmdCtx, pTransferCtx, enmDir, enmSource, idTransfer, &pTransfer);
2264
2265 /* As soon as we've created our transfer locally, report back INITIALIZED to the host.
2266 * This will initialize the transfer on the host, so that in turn reports INITIALIZED
2267 * back to us (see case down below).*/
2268 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
2269 RT_SUCCESS(rc)
2270 ? SHCLTRANSFERSTATUS_INITIALIZED : SHCLTRANSFERSTATUS_ERROR, rc);
2271 if (RT_SUCCESS(rc))
2272 rc = rc2;
2273 break;
2274 }
2275
2276 case SHCLTRANSFERSTATUS_INITIALIZED:
2277 {
2278 /* The host announces the transfer direction from its point of view, so inverse the direction here. */
2279 if (enmDir == SHCLTRANSFERDIR_TO_REMOTE) /* H -> G */
2280 {
2281 enmDir = SHCLTRANSFERDIR_FROM_REMOTE;
2282 enmSource = SHCLSOURCE_REMOTE;
2283 }
2284 else if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE) /* G -> H */
2285 {
2286 enmDir = SHCLTRANSFERDIR_TO_REMOTE;
2287 enmSource = SHCLSOURCE_LOCAL;
2288 }
2289 else
2290 AssertFailedBreakStmt(rc = VERR_INVALID_PARAMETER);
2291
2292 if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE) /* H->G */
2293 {
2294 /* The host reported INITIALIZED for the transfer.
2295 * So init our local transfer as well now. */
2296 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx, idTransfer);
2297 if (pTransfer)
2298 {
2299 rc = vbglR3ClipboardTransferInit(pCmdCtx, pTransfer);
2300
2301 /* Only send back a reply on error -- we already reported INITIALIZED
2302 * in the case SHCLTRANSFERSTATUS_REQUESTED above. */
2303 if (RT_FAILURE(rc))
2304 {
2305 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
2306 SHCLTRANSFERSTATUS_ERROR, rc);
2307 AssertRC(rc2);
2308 }
2309 }
2310 else
2311 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
2312 }
2313 else if (enmDir == SHCLTRANSFERDIR_TO_REMOTE) /* G->H */
2314 {
2315 /* The host reported the INITIALIZED status together with the transfer ID.
2316 * So create a local transfer here with that ID. */
2317 PSHCLTRANSFER pTransfer;
2318 rc = vbglR3ClipboardTransferCreate(pCmdCtx, pTransferCtx, enmDir, enmSource, idTransfer, &pTransfer);
2319 if (RT_SUCCESS(rc))
2320 rc = vbglR3ClipboardTransferInit(pCmdCtx, pTransfer);
2321
2322 /* Send a reply in any case. */
2323 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
2324 RT_SUCCESS(rc)
2325 ? SHCLTRANSFERSTATUS_INITIALIZED : SHCLTRANSFERSTATUS_ERROR, rc);
2326 if (RT_SUCCESS(rc))
2327 rc = rc2;
2328 }
2329 else
2330 AssertFailedBreakStmt(rc = VERR_INVALID_PARAMETER);
2331
2332 break;
2333 }
2334
2335 case SHCLTRANSFERSTATUS_UNINITIALIZED:
2336 {
2337 rc = vbglR3ClipboardTransferDestroy(pCmdCtx, pTransferCtx, idTransfer);
2338 break;
2339 }
2340
2341 case SHCLTRANSFERSTATUS_STARTED:
2342 {
2343 rc = vbglR3ClipboardTransferStart(pCmdCtx, pTransferCtx, idTransfer);
2344 break;
2345 }
2346
2347 case SHCLTRANSFERSTATUS_STOPPED:
2348 RT_FALL_THROUGH();
2349 case SHCLTRANSFERSTATUS_CANCELED:
2350 RT_FALL_THROUGH();
2351 case SHCLTRANSFERSTATUS_KILLED:
2352 RT_FALL_THROUGH();
2353 case SHCLTRANSFERSTATUS_ERROR:
2354 {
2355 rc = vbglR3ClipboardTransferStop(pCmdCtx, pTransferCtx, idTransfer);
2356 break;
2357 }
2358
2359 default:
2360 LogRel(("Shared Clipboard: Received unknown status %#x (%Rrc) for transfer %RU32\n",
2361 transferReport.uStatus, pEvent->u.TransferStatus.Report.rc, pEvent->u.TransferStatus.uID));
2362 rc = VERR_NOT_SUPPORTED;
2363 break;
2364 }
2365
2366 if (RT_SUCCESS(rc))
2367 {
2368 pEvent->u.TransferStatus.enmDir = enmDir;
2369 pEvent->u.TransferStatus.Report = transferReport;
2370 pEvent->u.TransferStatus.uID = VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext);
2371
2372 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_TRANSFER_STATUS;
2373 }
2374 }
2375 break;
2376 }
2377
2378 case VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ:
2379 {
2380 uint32_t fRoots;
2381 rc = VbglR3ClipboardTransferRootListHdrReadReq(pCmdCtx, &fRoots);
2382
2383 /** @todo Validate / handle fRoots. */
2384
2385 if (RT_SUCCESS(rc))
2386 {
2387 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2388 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2389 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2390
2391 SHCLLISTHDR rootListHdr;
2392 ShClTransferListHdrInit(&rootListHdr);
2393
2394 rootListHdr.cEntries = ShClTransferRootsCount(pTransfer);
2395
2396 LogFlowFunc(("cRoots=%RU32\n", rootListHdr.cEntries));
2397
2398 rc = VbglR3ClipboardTransferRootListHdrReadReply(pCmdCtx, &rootListHdr);
2399 }
2400 break;
2401 }
2402
2403 case VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ:
2404 {
2405 uint64_t uIndex;
2406 uint32_t fInfo;
2407 rc = VbglR3ClipboardTransferRootListEntryReadReq(pCmdCtx, &uIndex, &fInfo);
2408 if (RT_SUCCESS(rc))
2409 {
2410 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2411 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2412 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2413
2414 PCSHCLLISTENTRY pEntry = ShClTransferRootsEntryGet(pTransfer, uIndex);
2415 if (pEntry)
2416 {
2417 rc = VbglR3ClipboardTransferRootListEntryReadReply(pCmdCtx, uIndex, pEntry);
2418 }
2419 else
2420 rc = VERR_NOT_FOUND;
2421 }
2422 break;
2423 }
2424
2425 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN:
2426 {
2427 SHCLLISTOPENPARMS openParmsList;
2428 rc = ShClTransferListOpenParmsInit(&openParmsList);
2429 if (RT_SUCCESS(rc))
2430 {
2431 rc = VbglR3ClipboardTransferListOpenRecv(pCmdCtx, &openParmsList);
2432 if (RT_SUCCESS(rc))
2433 {
2434 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2435 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2436 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2437
2438 LogFlowFunc(("pszPath=%s\n", openParmsList.pszPath));
2439
2440 SHCLLISTHANDLE hList = NIL_SHCLLISTHANDLE;
2441 rc = ShClTransferListOpen(pTransfer, &openParmsList, &hList);
2442
2443 /* Reply in any case. */
2444 int rc2 = VbglR3ClipboardTransferListOpenReply(pCmdCtx, rc, hList);
2445 AssertRC(rc2);
2446 }
2447
2448 ShClTransferListOpenParmsDestroy(&openParmsList);
2449 }
2450
2451 break;
2452 }
2453
2454 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE:
2455 {
2456 SHCLLISTHANDLE hList;
2457 rc = VbglR3ClipboardTransferListCloseRecv(pCmdCtx, &hList);
2458 if (RT_SUCCESS(rc))
2459 {
2460 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2461 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2462 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2463
2464 rc = ShClTransferListClose(pTransfer, hList);
2465
2466 /* Reply in any case. */
2467 int rc2 = VbglR3ClipboardTransferListCloseReply(pCmdCtx, rc, hList);
2468 AssertRC(rc2);
2469 }
2470
2471 break;
2472 }
2473
2474 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ:
2475 {
2476 /** @todo Handle filter + list features. */
2477
2478 SHCLLISTHANDLE hList = NIL_SHCLLISTHANDLE;
2479 uint32_t fFlags = 0;
2480 rc = VbglR3ClipboardTransferListHdrReadRecvReq(pCmdCtx, &hList, &fFlags);
2481 if (RT_SUCCESS(rc))
2482 {
2483 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2484 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2485 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2486
2487 SHCLLISTHDR hdrList;
2488 rc = ShClTransferListGetHeader(pTransfer, hList, &hdrList);
2489 if (RT_SUCCESS(rc))
2490 {
2491 rc = VbglR3ClipboardTransferListHdrWrite(pCmdCtx, hList, &hdrList);
2492
2493 ShClTransferListHdrDestroy(&hdrList);
2494 }
2495 }
2496
2497 break;
2498 }
2499
2500 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ:
2501 {
2502 LogFlowFunc(("VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ\n"));
2503
2504 SHCLLISTENTRY entryList;
2505 rc = ShClTransferListEntryInit(&entryList);
2506 if (RT_SUCCESS(rc))
2507 {
2508 SHCLLISTHANDLE hList;
2509 uint32_t fInfo;
2510 rc = VbglR3ClipboardTransferListEntryReadRecvReq(pCmdCtx, &hList, &fInfo);
2511 if (RT_SUCCESS(rc))
2512 {
2513 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2514 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2515 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2516
2517 rc = ShClTransferListRead(pTransfer, hList, &entryList);
2518 if (RT_SUCCESS(rc))
2519 {
2520 PSHCLFSOBJINFO pObjInfo = (PSHCLFSOBJINFO)entryList.pvInfo;
2521 Assert(entryList.cbInfo == sizeof(SHCLFSOBJINFO));
2522
2523 RT_NOREF(pObjInfo);
2524
2525 LogFlowFunc(("\t%s (%RU64 bytes)\n", entryList.pszName, pObjInfo->cbObject));
2526
2527 rc = VbglR3ClipboardTransferListEntryWrite(pCmdCtx, hList, &entryList);
2528 }
2529 }
2530
2531 ShClTransferListEntryDestroy(&entryList);
2532 }
2533
2534 break;
2535 }
2536
2537 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN:
2538 {
2539 SHCLOBJOPENCREATEPARMS openParms;
2540 rc = ShClTransferObjOpenParmsInit(&openParms);
2541 if (RT_SUCCESS(rc))
2542 {
2543 rc = VbglR3ClipboardTransferObjOpenRecv(pCmdCtx, &openParms);
2544 if (RT_SUCCESS(rc))
2545 {
2546 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2547 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2548 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2549
2550 SHCLOBJHANDLE hObj;
2551 rc = ShClTransferObjOpen(pTransfer, &openParms, &hObj);
2552
2553 /* Reply in any case. */
2554 int rc2 = VbglR3ClipboardTransferObjOpenReply(pCmdCtx, rc, hObj);
2555 AssertRC(rc2);
2556 }
2557
2558 ShClTransferObjOpenParmsDestroy(&openParms);
2559 }
2560
2561 break;
2562 }
2563
2564 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE:
2565 {
2566 SHCLOBJHANDLE hObj;
2567 rc = VbglR3ClipboardTransferObjCloseRecv(pCmdCtx, &hObj);
2568 if (RT_SUCCESS(rc))
2569 {
2570 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2571 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2572 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2573
2574 rc = ShClTransferObjClose(pTransfer, hObj);
2575
2576 /* Reply in any case. */
2577 int rc2 = VbglR3ClipboardTransferObjCloseReply(pCmdCtx, rc, hObj);
2578 AssertRC(rc2);
2579 }
2580
2581 break;
2582 }
2583
2584 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ:
2585 {
2586 SHCLOBJHANDLE hObj;
2587 uint32_t cbBuf;
2588 uint32_t fFlags;
2589 rc = VbglR3ClipboardTransferObjReadRecv(pCmdCtx, &hObj, &cbBuf, &fFlags);
2590 if (RT_SUCCESS(rc))
2591 {
2592 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2593 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2594 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2595
2596 AssertBreakStmt(pCmdCtx->Transfers.cbChunkSize, rc = VERR_INVALID_PARAMETER);
2597
2598 const uint32_t cbToRead = RT_MIN(cbBuf, pCmdCtx->Transfers.cbChunkSize);
2599
2600 LogFlowFunc(("hObj=%RU64, cbBuf=%RU32, fFlags=0x%x -> cbChunkSize=%RU32, cbToRead=%RU32\n",
2601 hObj, cbBuf, fFlags, pCmdCtx->Transfers.cbChunkSize, cbToRead));
2602
2603 void *pvBuf = RTMemAlloc(cbToRead);
2604 if (pvBuf)
2605 {
2606 uint32_t cbRead;
2607 rc = ShClTransferObjRead(pTransfer, hObj, pvBuf, cbToRead, fFlags, &cbRead);
2608 if (RT_SUCCESS(rc))
2609 rc = VbglR3ClipboardTransferObjWriteSend(pCmdCtx, hObj, pvBuf, cbRead, NULL /* pcbWritten */);
2610
2611 RTMemFree(pvBuf);
2612 }
2613 else
2614 rc = VERR_NO_MEMORY;
2615 }
2616
2617 break;
2618 }
2619
2620 default:
2621 {
2622 rc = VbglR3ClipboardEventGetNext(idMsg, cParms, pCmdCtx, pEvent);
2623 if (RT_FAILURE(rc))
2624 fErrorSent = true;
2625 break;
2626 }
2627 }
2628
2629 if ( !fErrorSent
2630 && RT_FAILURE(rc))
2631 {
2632 /* Report error back to the host. */
2633 int rc2 = VbglR3ClipboardWriteError(pCmdCtx->idClient, rc);
2634 AssertRC(rc2);
2635 }
2636 }
2637 else
2638 {
2639 /*
2640 * This builds on what we did in VbglR3ClipboardMsgPeekWait, so
2641 * !HACK ALERT! cParms is the format flag or flags.
2642 */
2643 rc = VINF_SUCCESS;
2644 switch (idMsg)
2645 {
2646 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
2647 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
2648 pEvent->u.fReportedFormats = cParms;
2649 break;
2650
2651 case VBOX_SHCL_HOST_MSG_READ_DATA:
2652 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2653 pEvent->u.fReadData = cParms;
2654 break;
2655
2656 case VBOX_SHCL_HOST_MSG_QUIT:
2657 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
2658 break;
2659
2660 default:
2661 AssertMsgFailed(("%u (%#x)\n", idMsg, idMsg));
2662 rc = VERR_NOT_SUPPORTED;
2663 break;
2664 }
2665 }
2666
2667 LogFlowFuncLeaveRC(rc);
2668 return rc;
2669}
2670
2671#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
2672
2673VBGLR3DECL(int) VbglR3ClipboardEventGetNext(uint32_t idMsg, uint32_t cParms, PVBGLR3SHCLCMDCTX pCtx, PVBGLR3CLIPBOARDEVENT pEvent)
2674{
2675 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
2676 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
2677
2678 RT_NOREF(cParms);
2679
2680 int rc;
2681 if (!pCtx->fUseLegacyProtocol)
2682 {
2683 LogFunc(("Handling idMsg=%RU32 (%s)\n", idMsg, ShClHostMsgToStr(idMsg)));
2684 switch (idMsg)
2685 {
2686 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
2687 {
2688 rc = vbglR3ClipboardFormatsReportRecv(pCtx, &pEvent->u.fReportedFormats);
2689 if (RT_SUCCESS(rc))
2690 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
2691 break;
2692 }
2693
2694 case VBOX_SHCL_HOST_MSG_READ_DATA_CID:
2695 {
2696 rc = vbglR3ClipboardFetchReadDataCid(pCtx, &pEvent->u.fReadData);
2697 if (RT_SUCCESS(rc))
2698 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2699 break;
2700 }
2701
2702 case VBOX_SHCL_HOST_MSG_READ_DATA:
2703 {
2704 rc = vbglR3ClipboardFetchReadData(pCtx, &pEvent->u.fReadData);
2705 if (RT_SUCCESS(rc))
2706 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2707 break;
2708 }
2709
2710 case VBOX_SHCL_HOST_MSG_QUIT:
2711 {
2712 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
2713 rc = VINF_SUCCESS;
2714 break;
2715 }
2716
2717 default:
2718 {
2719 /** @todo r=bird: BUGBUG - need a skip command here! */
2720 rc = VERR_NOT_SUPPORTED;
2721 break;
2722 }
2723 }
2724
2725 if (RT_SUCCESS(rc))
2726 {
2727 /* Copy over our command context to the event. */
2728 pEvent->cmdCtx = *pCtx;
2729 }
2730 else
2731 {
2732 /* Report error back to the host. */
2733 int rc2 = VbglR3ClipboardWriteError(pCtx->idClient, rc);
2734 AssertRC(rc2);
2735 }
2736 }
2737 else
2738 {
2739 /*
2740 * This builds on what we did in VbglR3ClipboardMsgPeekWait, so
2741 * !HACK ALERT! cParms is the format flag or flags.
2742 */
2743 rc = VINF_SUCCESS;
2744 switch (idMsg)
2745 {
2746 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
2747 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
2748 pEvent->u.fReportedFormats = cParms;
2749 break;
2750
2751 case VBOX_SHCL_HOST_MSG_READ_DATA:
2752 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2753 pEvent->u.fReadData = cParms;
2754 break;
2755
2756 case VBOX_SHCL_HOST_MSG_QUIT:
2757 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
2758 break;
2759
2760 default:
2761 AssertMsgFailed(("%u (%#x)\n", idMsg, idMsg));
2762 rc = VERR_NOT_SUPPORTED;
2763 break;
2764 }
2765 pEvent->cmdCtx = *pCtx;
2766 }
2767
2768 LogFlowFuncLeaveRC(rc);
2769 return rc;
2770}
2771
2772/**
2773 * Frees (destroys) a formerly allocated Shared Clipboard event.
2774 *
2775 * @returns IPRT status code.
2776 * @param pEvent Event to free (destroy).
2777 */
2778VBGLR3DECL(void) VbglR3ClipboardEventFree(PVBGLR3CLIPBOARDEVENT pEvent)
2779{
2780 if (!pEvent)
2781 return;
2782
2783 /* Some messages require additional cleanup. */
2784 switch (pEvent->enmType)
2785 {
2786 default:
2787 break;
2788 }
2789
2790 RTMemFree(pEvent);
2791 pEvent = NULL;
2792}
2793
2794/**
2795 * Reports (advertises) guest clipboard formats to the host.
2796 *
2797 * Legacy function, do not use anymore.
2798 *
2799 * @returns VBox status code.
2800 * @param idClient The client id returned by VbglR3ClipboardConnect().
2801 * @param fFormats The formats to report.
2802 */
2803VBGLR3DECL(int) VbglR3ClipboardReportFormats(HGCMCLIENTID idClient, uint32_t fFormats)
2804{
2805 struct
2806 {
2807 VBGLIOCHGCMCALL Hdr;
2808 VBoxShClParmReportFormats Parms;
2809 } Msg;
2810
2811 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_REPORT_FORMATS, VBOX_SHCL_CPARMS_REPORT_FORMATS);
2812 VbglHGCMParmUInt32Set(&Msg.Parms.f32Formats, fFormats);
2813
2814 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
2815
2816 LogFlowFuncLeaveRC(rc);
2817 return rc;
2818}
2819
2820/**
2821 * Sends guest clipboard data to the host.
2822 *
2823 * Legacy function kept for compatibility, do not use anymore.
2824 *
2825 * This is usually called in reply to a VBOX_SHCL_HOST_MSG_READ_DATA message
2826 * from the host.
2827 *
2828 * @returns VBox status code.
2829 * @param idClient The client id returned by VbglR3ClipboardConnect().
2830 * @param fFormat The format of the data.
2831 * @param pvData Pointer to the data to send. Can be NULL if @a cbData
2832 * is zero.
2833 * @param cbData Number of bytes of data to send. Zero is valid.
2834 */
2835VBGLR3DECL(int) VbglR3ClipboardWriteData(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb)
2836{
2837 LogFlowFuncEnter();
2838
2839 struct
2840 {
2841 VBGLIOCHGCMCALL Hdr;
2842 VBoxShClParmDataWriteOld Parms;
2843 } Msg;
2844
2845 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_DATA_WRITE, VBOX_SHCL_CPARMS_DATA_WRITE_OLD);
2846 VbglHGCMParmUInt32Set(&Msg.Parms.f32Format, fFormat);
2847 VbglHGCMParmPtrSet(&Msg.Parms.pData, pv, cb);
2848
2849 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
2850
2851 LogFlowFuncLeaveRC(rc);
2852 return rc;
2853}
2854
2855/**
2856 * Sends guest clipboard data to the host.
2857 *
2858 * This is usually called in reply to a VBOX_SHCL_HOST_MSG_READ_DATA message
2859 * from the host.
2860 *
2861 * @returns VBox status code.
2862 * @param pCtx The command context returned by VbglR3ClipboardConnectEx().
2863 * @param fFormat Clipboard format to send.
2864 * @param pvData Pointer to the data to send. Can be NULL if @a cbData
2865 * is zero.
2866 * @param cbData Number of bytes of data to send. Zero is valid.
2867 */
2868VBGLR3DECL(int) VbglR3ClipboardWriteDataEx(PVBGLR3SHCLCMDCTX pCtx, SHCLFORMAT fFormat, void *pvData, uint32_t cbData)
2869{
2870 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
2871 AssertReturn(cbData == 0 || RT_VALID_PTR(pvData), VERR_INVALID_PARAMETER);
2872
2873 LogFlowFunc(("fFormat=%#x pvData=%p cbData=%#x\n", fFormat, pvData, cbData));
2874
2875 int rc;
2876 if (pCtx->fUseLegacyProtocol)
2877 rc = VbglR3ClipboardWriteData(pCtx->idClient, fFormat, pvData, cbData);
2878 else
2879 {
2880 struct
2881 {
2882 VBGLIOCHGCMCALL Hdr;
2883 VBoxShClParmDataWrite Parms;
2884 } Msg;
2885
2886 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_DATA_WRITE, VBOX_SHCL_CPARMS_DATA_WRITE);
2887 Msg.Parms.id64Context.SetUInt64(pCtx->idContext);
2888 Msg.Parms.f32Format.SetUInt32(fFormat);
2889 Msg.Parms.pData.SetPtr(pvData, cbData);
2890
2891 LogFlowFunc(("CID=%RU32\n", pCtx->idContext));
2892
2893 rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
2894 }
2895
2896 LogFlowFuncLeaveRC(rc);
2897 return rc;
2898}
2899
2900/**
2901 * Writes an error to the host.
2902 *
2903 * @returns IPRT status code.
2904 * @param idClient The client id returned by VbglR3ClipboardConnect().
2905 * @param rcErr Error (IPRT-style) to send.
2906 */
2907VBGLR3DECL(int) VbglR3ClipboardWriteError(HGCMCLIENTID idClient, int rcErr)
2908{
2909 AssertReturn(idClient, VERR_INVALID_PARAMETER);
2910
2911 VBoxShClWriteErrorMsg Msg;
2912 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHCL_GUEST_FN_ERROR, VBOX_SHCL_CPARMS_ERROR);
2913
2914 /** @todo Context ID not used yet. */
2915 Msg.uContext.SetUInt64(0);
2916 Msg.rc.SetUInt32((uint32_t)rcErr); /* uint32_t vs. int. */
2917
2918 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
2919
2920 if (RT_FAILURE(rc))
2921 LogFlowFunc(("Sending error %Rrc failed with rc=%Rrc\n", rcErr, rc));
2922 if (rc == VERR_NOT_SUPPORTED)
2923 rc = VINF_SUCCESS;
2924
2925 if (RT_FAILURE(rc))
2926 LogRel(("Shared Clipboard: Reporting error %Rrc to the host failed with %Rrc\n", rcErr, rc));
2927
2928 LogFlowFuncLeaveRC(rc);
2929 return rc;
2930}
2931
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