VirtualBox

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

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

Shared Clipboard: Relaxed transfer status checks a bit when reading the transfer root list. ​​​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.7 KB
Line 
1/* $Id: VBoxGuestR3LibClipboard.cpp 100405 2023-07-06 10:13:38Z 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 SHCLTRANSFERSTATUS const enmSts = ShClTransferGetStatus(pTransfer);
821 AssertMsgReturn( enmSts == SHCLTRANSFERSTATUS_INITIALIZED
822 || enmSts == SHCLTRANSFERSTATUS_STARTED,
823 ("Can't read root list -- wrong transfer status (%#x)\n", enmSts), VERR_WRONG_ORDER);
824
825 SHCLLISTHDR Hdr;
826 int rc = vbglR3ClipboardTransferRootListHdrRead(pCtx, &Hdr);
827 if (RT_SUCCESS(rc))
828 {
829 LogFlowFunc(("cEntries=%RU64, cTotalSize=%RU64\n", Hdr.cEntries, Hdr.cbTotalSize));
830
831 if (!Hdr.cEntries) /* Should never happen (tm). */
832 {
833#ifdef DEBUG_andy
834 AssertFailed();
835#endif
836 LogRel(("Shared Clipboard: Warning: Transfer %RU32 has no entries\n", ShClTransferGetID(pTransfer)));
837 }
838
839 for (uint64_t i = 0; i < Hdr.cEntries; i++)
840 {
841 PSHCLLISTENTRY pEntry = NULL;
842 rc = ShClTransferListEntryAlloc(&pEntry);
843 if (RT_SUCCESS(rc))
844 {
845 rc = vbglR3ClipboardTransferRootListEntryRead(pCtx, i, pEntry);
846 if (RT_SUCCESS(rc))
847 rc = ShClTransferListAddEntry(&pTransfer->lstRoots, pEntry, true /* fAppend */);
848 }
849
850 if (RT_FAILURE(rc))
851 {
852 ShClTransferListEntryFree(pEntry);
853 break;
854 }
855 }
856 }
857 else
858 LogRel(("Shared Clipboard: Reading root list for transfer %RU32 failed: %Rrc\n", ShClTransferGetID(pTransfer), rc));
859
860 LogFlowFuncLeaveRC(rc);
861 return rc;
862}
863
864/**
865 * Receives a transfer status from the host.
866 *
867 * @returns VBox status code.
868 * @param pCtx Shared Clipboard command context to use for the connection.
869 * @param pEnmDir Where to store the transfer direction for the reported transfer.
870 * @param pReport Where to store the transfer (status) report.
871 */
872VBGLR3DECL(int) VbglR3ClipboarTransferStatusRecv(PVBGLR3SHCLCMDCTX pCtx,
873 PSHCLTRANSFERDIR pEnmDir, PSHCLTRANSFERREPORT pReport)
874{
875 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
876 AssertPtrReturn(pReport, VERR_INVALID_POINTER);
877 AssertPtrReturn(pEnmDir, VERR_INVALID_POINTER);
878
879 VBoxShClTransferStatusMsg Msg;
880 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
881 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_TRANSFER_STATUS);
882
883 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_STATUS);
884 Msg.enmDir.SetUInt32(0);
885 Msg.enmStatus.SetUInt32(0);
886 Msg.rc.SetUInt32(0);
887 Msg.fFlags.SetUInt32(0);
888
889 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
890 if (RT_SUCCESS(rc))
891 {
892 rc = Msg.uContext.GetUInt64(&pCtx->idContext); AssertRC(rc);
893 if (RT_SUCCESS(rc))
894 {
895 rc = Msg.enmDir.GetUInt32((uint32_t *)pEnmDir);
896 AssertRC(rc);
897 }
898 if (RT_SUCCESS(rc))
899 {
900 rc = Msg.enmStatus.GetUInt32(&pReport->uStatus);
901 AssertRC(rc);
902 }
903 if (RT_SUCCESS(rc))
904 {
905 rc = Msg.rc.GetUInt32((uint32_t *)&pReport->rc);
906 AssertRC(rc);
907 }
908 if (RT_SUCCESS(rc))
909 {
910 rc = Msg.fFlags.GetUInt32(&pReport->fFlags);
911 AssertRC(rc);
912 }
913 }
914
915 LogFlowFuncLeaveRC(rc);
916 return rc;
917}
918
919/**
920 * Replies to a transfer report from the host, extended version.
921 *
922 * @returns VBox status code.
923 * @param pCtx Shared Clipboard command context to use for the connection.
924 * @param uCID Context ID to use.
925 * The transfer ID is part of this.
926 * @param uStatus Tranfer status to reply.
927 * @param rcTransfer Result code (rc) to reply.
928 */
929static int vbglR3ClipboardTransferStatusReplyEx(PVBGLR3SHCLCMDCTX pCtx, uint64_t uCID,
930 SHCLTRANSFERSTATUS uStatus, int rcTransfer)
931{
932 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
933
934 VBoxShClReplyMsg Msg;
935 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
936 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
937
938 Msg.uContext.SetUInt64(uCID);
939 Msg.enmType.SetUInt32(VBOX_SHCL_TX_REPLYMSGTYPE_TRANSFER_STATUS);
940 Msg.rc.SetUInt32((uint32_t )rcTransfer); /* int vs. uint32_t */
941 Msg.pvPayload.SetPtr(NULL, 0);
942
943 Msg.u.TransferStatus.enmStatus.SetUInt32((uint32_t)uStatus);
944
945 LogFlowFunc(("%s\n", ShClTransferStatusToStr(uStatus)));
946
947 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
948
949 LogFlowFuncLeaveRC(rc);
950 return rc;
951}
952
953/**
954 * Replies to a transfer report from the host.
955 *
956 * @returns VBox status code.
957 * @param pCtx Shared Clipboard command context to use for the connection.
958 * @param pTransfer Transfer of report to reply to.
959 * @param uStatus Tranfer status to reply.
960 * @param rcTransfer Result code (rc) to reply.
961 */
962VBGLR3DECL(int) VbglR3ClipboardTransferStatusReply(PVBGLR3SHCLCMDCTX pCtx, PSHCLTRANSFER pTransfer,
963 SHCLTRANSFERSTATUS uStatus, int rcTransfer)
964{
965 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
966 RT_NOREF(pTransfer); /* Currently not used (yet). */
967
968 int rc = vbglR3ClipboardTransferStatusReplyEx(pCtx, pCtx->idContext, uStatus, rcTransfer);
969
970 LogFlowFuncLeaveRC(rc);
971 return rc;
972}
973
974/**
975 * Receives a host request to read a transfer root list header from the guest.
976 *
977 * @returns VBox status code.
978 * @param pCtx Shared Clipboard command context to use for the connection.
979 * @param pfRoots Where to store the root list header flags to use, requested by the host.
980 */
981VBGLR3DECL(int) VbglR3ClipboardTransferRootListHdrReadReq(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pfRoots)
982{
983 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
984 AssertPtrReturn(pfRoots, VERR_INVALID_POINTER);
985
986 VBoxShClRootListReadReqMsg Msg;
987 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
988 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ_REQ);
989
990 Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ);
991 Msg.ReqParms.fRoots.SetUInt32(0);
992
993 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
994 if (RT_SUCCESS(rc))
995 {
996 rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext); AssertRC(rc);
997 if (RT_SUCCESS(rc))
998 {
999 rc = Msg.ReqParms.fRoots.GetUInt32(pfRoots);
1000 AssertRC(rc);
1001 }
1002 }
1003
1004 LogFlowFuncLeaveRC(rc);
1005 return rc;
1006}
1007
1008/**
1009 * Replies to a transfer root list header request.
1010 *
1011 * @returns VBox status code.
1012 * @param pCtx Shared Clipboard command context to use for the connection.
1013 * @param pRootListHdr Root lsit header to reply to the host.
1014 */
1015VBGLR3DECL(int) VbglR3ClipboardTransferRootListHdrReadReply(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHDR pRootListHdr)
1016{
1017 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1018 AssertPtrReturn(pRootListHdr, VERR_INVALID_POINTER);
1019
1020 VBoxShClRootListHdrMsg Msg;
1021 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1022 VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_WRITE, VBOX_SHCL_CPARMS_ROOT_LIST_HDR_WRITE);
1023
1024 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1025 Msg.ReqParms.fRoots.SetUInt32(pRootListHdr->fFeatures);
1026
1027 Msg.cRoots.SetUInt64(pRootListHdr->cEntries);
1028
1029 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1030
1031 LogFlowFuncLeaveRC(rc);
1032 return rc;
1033}
1034
1035/**
1036 * Receives a host request to read a transfer root list entry from the guest.
1037 *
1038 * @returns VBox status code.
1039 * @param pCtx Shared Clipboard command context to use for the connection.
1040 * @param puIndex Where to return the index of the root list entry the host wants to read.
1041 * @param pfInfo Where to return the read flags the host wants to use.
1042 */
1043VBGLR3DECL(int) VbglR3ClipboardTransferRootListEntryReadReq(PVBGLR3SHCLCMDCTX pCtx, uint64_t *puIndex, uint32_t *pfInfo)
1044{
1045 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1046 AssertPtrReturn(puIndex, VERR_INVALID_POINTER);
1047 AssertPtrReturn(pfInfo, VERR_INVALID_POINTER);
1048
1049 VBoxShClRootListEntryReadReqMsg Msg;
1050 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1051 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ_REQ);
1052
1053 Msg.Parms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ);
1054 Msg.Parms.fInfo.SetUInt32(0);
1055 Msg.Parms.uIndex.SetUInt64(0);
1056
1057 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1058 if (RT_SUCCESS(rc))
1059 {
1060 rc = Msg.Parms.uContext.GetUInt64(&pCtx->idContext); AssertRC(rc);
1061 if (RT_SUCCESS(rc))
1062 {
1063 rc = Msg.Parms.fInfo.GetUInt32(pfInfo);
1064 AssertRC(rc);
1065 }
1066 if (RT_SUCCESS(rc))
1067 {
1068 rc = Msg.Parms.uIndex.GetUInt64(puIndex);
1069 AssertRC(rc);
1070 }
1071 }
1072
1073 LogFlowFuncLeaveRC(rc);
1074 return rc;
1075}
1076
1077/**
1078 * Replies to a transfer root list entry read request from the host.
1079 *
1080 * @returns VBox status code.
1081 * @param pCtx Shared Clipboard command context to use for the connection.
1082 * @param uIndex Index of root list entry to reply.
1083 * @param pEntry Actual root list entry to reply.
1084 */
1085VBGLR3DECL(int) VbglR3ClipboardTransferRootListEntryReadReply(PVBGLR3SHCLCMDCTX pCtx, uint32_t uIndex, PSHCLLISTENTRY pEntry)
1086{
1087 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1088 AssertPtrReturn(pEntry, VERR_INVALID_POINTER);
1089
1090 VBoxShClRootListEntryMsg Msg;
1091 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1092 VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_WRITE, VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_WRITE);
1093
1094 Msg.Parms.uContext.SetUInt64(pCtx->idContext);
1095 Msg.Parms.fInfo.SetUInt32(pEntry->fInfo);
1096 Msg.Parms.uIndex.SetUInt64(uIndex);
1097
1098 Msg.szName.SetPtr(pEntry->pszName, pEntry->cbName);
1099 Msg.cbInfo.SetUInt32(pEntry->cbInfo);
1100 Msg.pvInfo.SetPtr(pEntry->pvInfo, pEntry->cbInfo);
1101
1102 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1103
1104 LogFlowFuncLeaveRC(rc);
1105 return rc;
1106}
1107
1108/**
1109 * Sends a request to open a transfer list handle to the host.
1110 *
1111 * @returns VBox status code.
1112 * @param pCtx Shared Clipboard command context to use for the connection.
1113 * @param pOpenParms List open parameters to use for the open request.
1114 * @param phList Where to return the list handle received from the host.
1115 */
1116VBGLR3DECL(int) VbglR3ClipboardTransferListOpenSend(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTOPENPARMS pOpenParms,
1117 PSHCLLISTHANDLE phList)
1118{
1119 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1120 AssertPtrReturn(pOpenParms, VERR_INVALID_POINTER);
1121 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1122
1123 VBoxShClListOpenMsg Msg;
1124 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1125 VBOX_SHCL_GUEST_FN_LIST_OPEN, VBOX_SHCL_CPARMS_LIST_OPEN);
1126
1127 Msg.uContext.SetUInt64(pCtx->idContext);
1128 Msg.fList.SetUInt32(0);
1129 Msg.pvFilter.SetPtr(pOpenParms->pszFilter, pOpenParms->cbFilter);
1130 Msg.pvPath.SetPtr(pOpenParms->pszPath, pOpenParms->cbPath);
1131 Msg.uHandle.SetUInt64(0);
1132
1133 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1134 if (RT_SUCCESS(rc))
1135 {
1136 rc = Msg.uHandle.GetUInt64(phList); AssertRC(rc);
1137 }
1138
1139 LogFlowFuncLeaveRC(rc);
1140 return rc;
1141}
1142
1143/**
1144 * Receives a host request to open a transfer list handle on the guest.
1145 *
1146 * @returns VBox status code.
1147 * @param pCtx Shared Clipboard command context to use for the connection.
1148 * @param pOpenParms Where to store the open parameters the host wants to use for opening the list handle.
1149 */
1150VBGLR3DECL(int) VbglR3ClipboardTransferListOpenRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTOPENPARMS pOpenParms)
1151{
1152 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1153 AssertPtrReturn(pOpenParms, VERR_INVALID_POINTER);
1154
1155 VBoxShClListOpenMsg Msg;
1156 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1157 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_OPEN);
1158
1159 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN);
1160 Msg.fList.SetUInt32(0);
1161 Msg.pvPath.SetPtr(pOpenParms->pszPath, pOpenParms->cbPath);
1162 Msg.pvFilter.SetPtr(pOpenParms->pszFilter, pOpenParms->cbFilter);
1163 Msg.uHandle.SetUInt64(0);
1164
1165 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1166 if (RT_SUCCESS(rc))
1167 {
1168 rc = Msg.uContext.GetUInt64(&pCtx->idContext);
1169 if (RT_SUCCESS(rc))
1170 rc = Msg.fList.GetUInt32(&pOpenParms->fList);
1171 }
1172
1173 LogFlowFuncLeaveRC(rc);
1174 return rc;
1175}
1176
1177/**
1178 * Replies to a transfer list open request from the host.
1179 *
1180 * @returns VBox status code.
1181 * @param pCtx Shared Clipboard command context to use for the connection.
1182 * @param rcReply Return code to reply to the host.
1183 * @param hList List handle of (guest) list to reply to the host.
1184 */
1185VBGLR3DECL(int) VbglR3ClipboardTransferListOpenReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLLISTHANDLE hList)
1186{
1187 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1188
1189 VBoxShClReplyMsg Msg;
1190 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1191 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1192
1193 Msg.uContext.SetUInt64(pCtx->idContext);
1194 Msg.enmType.SetUInt32(VBOX_SHCL_TX_REPLYMSGTYPE_LIST_OPEN);
1195 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1196 Msg.pvPayload.SetPtr(NULL, 0);
1197
1198 Msg.u.ListOpen.uHandle.SetUInt64(hList);
1199
1200 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1201
1202 LogFlowFuncLeaveRC(rc);
1203 return rc;
1204}
1205
1206/**
1207 * Receives a host request to close a list handle on the guest.
1208 *
1209 * @returns VBox status code.
1210 * @param pCtx Shared Clipboard command context to use for the connection.
1211 * @param phList Where to store the list handle to close, received from the host.
1212 */
1213VBGLR3DECL(int) VbglR3ClipboardTransferListCloseRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList)
1214{
1215 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1216 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1217
1218 VBoxShClListCloseMsg Msg;
1219 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1220 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_CLOSE);
1221
1222 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE);
1223 Msg.uHandle.SetUInt64(0);
1224
1225 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1226 if (RT_SUCCESS(rc))
1227 {
1228 rc = Msg.uContext.GetUInt64(&pCtx->idContext);
1229 if (RT_SUCCESS(rc))
1230 {
1231 rc = Msg.uHandle.GetUInt64(phList);
1232 AssertRC(rc);
1233 }
1234 }
1235
1236 LogFlowFuncLeaveRC(rc);
1237 return rc;
1238}
1239
1240/**
1241 * Replies to a transfer list handle close request from the host.
1242 *
1243 * @returns VBox status code.
1244 * @param pCtx Shared Clipboard command context to use for the connection.
1245 * @param rcReply Return code to reply to the host.
1246 * @param hList List handle the send the close reply for.
1247 */
1248VBGLR3DECL(int) VbglR3ClipboardTransferListCloseReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLLISTHANDLE hList)
1249{
1250 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1251
1252 VBoxShClReplyMsg Msg;
1253 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1254 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1255
1256 Msg.uContext.SetUInt64(pCtx->idContext);
1257 Msg.enmType.SetUInt32(VBOX_SHCL_TX_REPLYMSGTYPE_LIST_CLOSE);
1258 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1259 Msg.pvPayload.SetPtr(NULL, 0);
1260
1261 Msg.u.ListOpen.uHandle.SetUInt64(hList);
1262
1263 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1264
1265 LogFlowFuncLeaveRC(rc);
1266 return rc;
1267}
1268
1269/**
1270 * Sends a request to close a transfer list handle to the host.
1271 *
1272 * @returns VBox status code.
1273 * @param pCtx Shared Clipboard command context to use for the connection.
1274 * @param hList List handle to request for closing on the host.
1275 */
1276VBGLR3DECL(int) VbglR3ClipboardTransferListCloseSend(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList)
1277{
1278 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1279
1280 VBoxShClListCloseMsg Msg;
1281 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1282 VBOX_SHCL_GUEST_FN_LIST_CLOSE, VBOX_SHCL_CPARMS_LIST_CLOSE);
1283
1284 Msg.uContext.SetUInt64(pCtx->idContext);
1285 Msg.uHandle.SetUInt64(hList);
1286
1287 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1288
1289 LogFlowFuncLeaveRC(rc);
1290 return rc;
1291}
1292
1293/**
1294 * Sends a request to read a transfer list header to the host.
1295 *
1296 * @returns VBox status code.
1297 * @param pCtx Shared Clipboard command context to use for the connection.
1298 * @param hList List handle to read list header for.
1299 * @param fFlags List header read flags to use.
1300 * @param pListHdr Where to return the list header received from the host.
1301 */
1302VBGLR3DECL(int) VbglR3ClipboardTransferListHdrRead(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList, uint32_t fFlags,
1303 PSHCLLISTHDR pListHdr)
1304{
1305 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1306 AssertPtrReturn(pListHdr, VERR_INVALID_POINTER);
1307
1308 VBoxShClListHdrMsg Msg;
1309 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1310 VBOX_SHCL_GUEST_FN_LIST_HDR_READ, VBOX_SHCL_CPARMS_LIST_HDR);
1311
1312 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1313 Msg.ReqParms.uHandle.SetUInt64(hList);
1314 Msg.ReqParms.fFlags.SetUInt32(fFlags);
1315
1316 Msg.fFeatures.SetUInt32(0);
1317 Msg.cbTotalSize.SetUInt32(0);
1318 Msg.cTotalObjects.SetUInt64(0);
1319 Msg.cbTotalSize.SetUInt64(0);
1320
1321 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1322 if (RT_SUCCESS(rc))
1323 {
1324 rc = Msg.fFeatures.GetUInt32(&pListHdr->fFeatures);
1325 if (RT_SUCCESS(rc))
1326 rc = Msg.cTotalObjects.GetUInt64(&pListHdr->cEntries);
1327 if (RT_SUCCESS(rc))
1328 rc = Msg.cbTotalSize.GetUInt64(&pListHdr->cbTotalSize);
1329 }
1330
1331 LogFlowFuncLeaveRC(rc);
1332 return rc;
1333}
1334
1335/**
1336 * Receives a host request to read a transfer list header on the guest.
1337 *
1338 * @returns VBox status code.
1339 * @param pCtx Shared Clipboard command context to use for the connection.
1340 * @param phList Where to return the list handle to read list header for.
1341 * @param pfFlags Where to return the List header read flags to use.
1342 */
1343VBGLR3DECL(int) VbglR3ClipboardTransferListHdrReadRecvReq(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList, uint32_t *pfFlags)
1344{
1345 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1346 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1347 AssertPtrReturn(pfFlags, VERR_INVALID_POINTER);
1348
1349 VBoxShClListHdrReadReqMsg Msg;
1350 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1351 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_HDR_READ_REQ);
1352
1353 Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ);
1354 Msg.ReqParms.uHandle.SetUInt64(0);
1355 Msg.ReqParms.fFlags.SetUInt32(0);
1356
1357 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1358 if (RT_SUCCESS(rc))
1359 {
1360 rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext);
1361 if (RT_SUCCESS(rc))
1362 rc = Msg.ReqParms.uHandle.GetUInt64(phList);
1363 if (RT_SUCCESS(rc))
1364 rc = Msg.ReqParms.fFlags.GetUInt32(pfFlags);
1365 }
1366
1367 LogFlowFuncLeaveRC(rc);
1368 return rc;
1369}
1370
1371/**
1372 * Sends (writes) a transfer list header to the host.
1373 *
1374 * @returns VBox status code.
1375 * @param pCtx Shared Clipboard command context to use for the connection.
1376 * @param hList List handle to write list header for.
1377 * @param pListHdr List header to write.
1378 */
1379VBGLR3DECL(int) VbglR3ClipboardTransferListHdrWrite(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList,
1380 PSHCLLISTHDR pListHdr)
1381{
1382 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1383 AssertPtrReturn(pListHdr, VERR_INVALID_POINTER);
1384
1385 VBoxShClListHdrMsg Msg;
1386 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1387 VBOX_SHCL_GUEST_FN_LIST_HDR_WRITE, VBOX_SHCL_CPARMS_LIST_HDR);
1388
1389 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1390 Msg.ReqParms.uHandle.SetUInt64(hList);
1391 Msg.ReqParms.fFlags.SetUInt32(0);
1392
1393 Msg.fFeatures.SetUInt32(0);
1394 Msg.cbTotalSize.SetUInt32(pListHdr->fFeatures);
1395 Msg.cTotalObjects.SetUInt64(pListHdr->cEntries);
1396 Msg.cbTotalSize.SetUInt64(pListHdr->cbTotalSize);
1397
1398 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1399
1400 LogFlowFuncLeaveRC(rc);
1401 return rc;
1402}
1403
1404/**
1405 * Sends a request to read a transfer list entry from the host.
1406 *
1407 * @returns VBox status code.
1408 * @param pCtx Shared Clipboard command context to use for the connection.
1409 * @param hList List handle to request to read a list entry for.
1410 * @param pListEntry Where to return the list entry read from the host.
1411 */
1412VBGLR3DECL(int) VbglR3ClipboardTransferListEntryRead(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList,
1413 PSHCLLISTENTRY pListEntry)
1414{
1415 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1416 AssertPtrReturn(pListEntry, VERR_INVALID_POINTER);
1417
1418 VBoxShClListEntryMsg Msg;
1419 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1420 VBOX_SHCL_GUEST_FN_LIST_ENTRY_READ, VBOX_SHCL_CPARMS_LIST_ENTRY);
1421
1422 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1423 Msg.ReqParms.uHandle.SetUInt64(hList);
1424 Msg.ReqParms.fInfo.SetUInt32(0);
1425
1426 Msg.szName.SetPtr(pListEntry->pszName, pListEntry->cbName);
1427 Msg.cbInfo.SetUInt32(pListEntry->cbInfo);
1428 Msg.pvInfo.SetPtr(pListEntry->pvInfo, pListEntry->cbInfo);
1429
1430 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1431 if (RT_SUCCESS(rc))
1432 {
1433 rc = Msg.cbInfo.GetUInt32(&pListEntry->cbInfo); AssertRC(rc);
1434 }
1435
1436 LogFlowFuncLeaveRC(rc);
1437 return rc;
1438}
1439
1440/**
1441 * Receives a host request to read a transfer list entry from the guest.
1442 *
1443 * @returns VBox status code.
1444 * @param pCtx Shared Clipboard command context to use for the connection.
1445 * @param phList Where to return the list handle to read a list entry for.
1446 * @param pfInfo Where to return the list read flags.
1447 */
1448VBGLR3DECL(int) VbglR3ClipboardTransferListEntryReadRecvReq(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList, uint32_t *pfInfo)
1449{
1450 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1451 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1452 AssertPtrReturn(pfInfo, VERR_INVALID_POINTER);
1453
1454 VBoxShClListEntryReadReqMsg Msg;
1455 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1456 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_ENTRY_READ);
1457
1458 Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ);
1459 Msg.ReqParms.uHandle.SetUInt64(0);
1460 Msg.ReqParms.fInfo.SetUInt32(0);
1461
1462 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1463 if (RT_SUCCESS(rc))
1464 {
1465 rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext);
1466 if (RT_SUCCESS(rc))
1467 {
1468 rc = Msg.ReqParms.uHandle.GetUInt64(phList);
1469 AssertRC(rc);
1470 }
1471 if (RT_SUCCESS(rc))
1472 {
1473 rc = Msg.ReqParms.fInfo.GetUInt32(pfInfo);
1474 AssertRC(rc);
1475 }
1476 }
1477
1478 LogFlowFuncLeaveRC(rc);
1479 return rc;
1480}
1481
1482/**
1483 * Sends (writes) a transfer list entry to the host.
1484 *
1485 * @returns VBox status code.
1486 * @param pCtx Shared Clipboard command context to use for the connection.
1487 * @param hList List handle to write a list etnry for.
1488 * @param pListEntry List entry to write.
1489 */
1490VBGLR3DECL(int) VbglR3ClipboardTransferListEntryWrite(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList,
1491 PSHCLLISTENTRY pListEntry)
1492{
1493 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1494 AssertPtrReturn(pListEntry, VERR_INVALID_POINTER);
1495
1496 VBoxShClListEntryMsg Msg;
1497 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1498 VBOX_SHCL_GUEST_FN_LIST_ENTRY_WRITE, VBOX_SHCL_CPARMS_LIST_ENTRY);
1499
1500 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1501 Msg.ReqParms.uHandle.SetUInt64(hList);
1502 Msg.ReqParms.fInfo.SetUInt32(pListEntry->fInfo);
1503
1504 Msg.szName.SetPtr(pListEntry->pszName, pListEntry->cbName);
1505 Msg.cbInfo.SetUInt32(pListEntry->cbInfo);
1506 Msg.pvInfo.SetPtr(pListEntry->pvInfo, pListEntry->cbInfo);
1507
1508 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1509
1510 LogFlowFuncLeaveRC(rc);
1511 return rc;
1512}
1513
1514/**
1515 * Receives a host request to open a transfer object on the guest.
1516 *
1517 * @returns VBox status code.
1518 * @param pCtx Shared Clipboard command context to use for the connection.
1519 * @param pCreateParms Where to store the object open/create parameters received from the host.
1520 */
1521VBGLR3DECL(int) VbglR3ClipboardTransferObjOpenRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms)
1522{
1523 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1524 AssertPtrReturn(pCreateParms, VERR_INVALID_POINTER);
1525
1526 VBoxShClObjOpenMsg Msg;
1527 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1528 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_OBJ_OPEN);
1529
1530 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN);
1531 Msg.uHandle.SetUInt64(0);
1532 Msg.szPath.SetPtr(pCreateParms->pszPath, pCreateParms->cbPath);
1533 Msg.fCreate.SetUInt32(0);
1534
1535 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1536 if (RT_SUCCESS(rc))
1537 {
1538 rc = Msg.uContext.GetUInt64(&pCtx->idContext);
1539 if (RT_SUCCESS(rc))
1540 rc = Msg.fCreate.GetUInt32(&pCreateParms->fCreate);
1541 }
1542
1543 LogFlowFuncLeaveRC(rc);
1544 return rc;
1545}
1546
1547/**
1548 * Replies a host request to open a transfer object.
1549 *
1550 * @returns VBox status code.
1551 * @param pCtx Shared Clipboard command context to use for the connection.
1552 * @param rcReply Return code to reply to the host.
1553 * @param hObj Object handle of opened object to reply to the host.
1554 */
1555VBGLR3DECL(int) VbglR3ClipboardTransferObjOpenReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLOBJHANDLE hObj)
1556{
1557 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1558
1559 VBoxShClReplyMsg Msg;
1560 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1561 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1562
1563 Msg.uContext.SetUInt64(pCtx->idContext);
1564 Msg.enmType.SetUInt32(VBOX_SHCL_TX_REPLYMSGTYPE_OBJ_OPEN);
1565 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1566 Msg.pvPayload.SetPtr(NULL, 0);
1567
1568 Msg.u.ObjOpen.uHandle.SetUInt64(hObj);
1569
1570 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1571
1572 LogFlowFuncLeaveRC(rc);
1573 return rc;
1574}
1575
1576/**
1577 * Sends a transfer object open request to the host.
1578 *
1579 * @returns VBox status code.
1580 * @param pCtx Shared Clipboard command context to use for the connection.
1581 * @param pCreateParms Object open/create parameters to use for opening the object on the host.
1582 * @param phObj Where to return the object handle from the host.
1583 */
1584VBGLR3DECL(int) VbglR3ClipboardTransferObjOpenSend(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms,
1585 PSHCLOBJHANDLE phObj)
1586{
1587 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1588 AssertPtrReturn(pCreateParms, VERR_INVALID_POINTER);
1589 AssertPtrReturn(phObj, VERR_INVALID_POINTER);
1590
1591 VBoxShClObjOpenMsg Msg;
1592 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1593 VBOX_SHCL_GUEST_FN_OBJ_OPEN, VBOX_SHCL_CPARMS_OBJ_OPEN);
1594
1595 Msg.uContext.SetUInt64(pCtx->idContext);
1596 Msg.uHandle.SetUInt64(0);
1597 Msg.szPath.SetPtr((void *)pCreateParms->pszPath, pCreateParms->cbPath);
1598 Msg.fCreate.SetUInt32(pCreateParms->fCreate);
1599
1600 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1601 if (RT_SUCCESS(rc))
1602 {
1603 Msg.uHandle.GetUInt64(phObj);
1604 }
1605
1606 LogFlowFuncLeaveRC(rc);
1607 return rc;
1608}
1609
1610/**
1611 * Receives a host request to close a transfer object on the guest.
1612 *
1613 * @returns VBox status code.
1614 * @param pCtx Shared Clipboard command context to use for the connection.
1615 * @param phObj Where to return the object handle to close from the host.
1616 */
1617VBGLR3DECL(int) VbglR3ClipboardTransferObjCloseRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJHANDLE phObj)
1618{
1619 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1620 AssertPtrReturn(phObj, VERR_INVALID_POINTER);
1621
1622 VBoxShClObjCloseMsg Msg;
1623 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1624 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_OBJ_CLOSE);
1625
1626 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE);
1627 Msg.uHandle.SetUInt64(0);
1628
1629 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1630 if (RT_SUCCESS(rc))
1631 {
1632 rc = Msg.uContext.GetUInt64(&pCtx->idContext);
1633 if (RT_SUCCESS(rc))
1634 rc = Msg.uHandle.GetUInt64(phObj);
1635 }
1636
1637 LogFlowFuncLeaveRC(rc);
1638 return rc;
1639}
1640
1641/**
1642 * Replies to a transfer object open request from the host.
1643 *
1644 * @returns VBox status code.
1645 * @param pCtx Shared Clipboard command context to use for the connection.
1646 * @param rcReply Return code to reply to the host.
1647 * @param hObj Object handle to reply to the host.
1648 */
1649VBGLR3DECL(int) VbglR3ClipboardTransferObjCloseReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLOBJHANDLE hObj)
1650{
1651 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1652
1653 VBoxShClReplyMsg Msg;
1654 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1655 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1656
1657 Msg.uContext.SetUInt64(pCtx->idContext);
1658 Msg.enmType.SetUInt32(VBOX_SHCL_TX_REPLYMSGTYPE_OBJ_CLOSE);
1659 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1660 Msg.pvPayload.SetPtr(NULL, 0);
1661
1662 Msg.u.ObjClose.uHandle.SetUInt64(hObj);
1663
1664 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1665
1666 LogFlowFuncLeaveRC(rc);
1667 return rc;
1668}
1669
1670/**
1671 * Sends a request to close a transfer object to the host.
1672 *
1673 * @returns VBox status code.
1674 * @param pCtx Shared Clipboard command context to use for the connection.
1675 * @param hObj Object handle to close on the host.
1676 */
1677VBGLR3DECL(int) VbglR3ClipboardTransferObjCloseSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj)
1678{
1679 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1680
1681 VBoxShClObjCloseMsg Msg;
1682 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1683 VBOX_SHCL_GUEST_FN_OBJ_CLOSE, VBOX_SHCL_CPARMS_OBJ_CLOSE);
1684
1685 Msg.uContext.SetUInt64(pCtx->idContext);
1686 Msg.uHandle.SetUInt64(hObj);
1687
1688 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1689
1690 LogFlowFuncLeaveRC(rc);
1691 return rc;
1692}
1693
1694/**
1695 * Receives a host request to read from a transfer object on the guest.
1696 *
1697 * @returns VBox status code.
1698 * @param pCtx Shared Clipboard command context to use for the connection.
1699 * @param phObj Where to return the object handle to read from.
1700 * @param pcbToRead Where to return the amount (in bytes) to read.
1701 * @param pfFlags Where to return the read flags.
1702 */
1703VBGLR3DECL(int) VbglR3ClipboardTransferObjReadRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJHANDLE phObj, uint32_t *pcbToRead,
1704 uint32_t *pfFlags)
1705{
1706 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1707 AssertPtrReturn(phObj, VERR_INVALID_POINTER);
1708 AssertPtrReturn(pcbToRead, VERR_INVALID_POINTER);
1709 AssertPtrReturn(pfFlags, VERR_INVALID_POINTER);
1710
1711 VBoxShClObjReadReqMsg Msg;
1712 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1713 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_OBJ_READ_REQ);
1714
1715 Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ);
1716 Msg.ReqParms.uHandle.SetUInt64(0);
1717 Msg.ReqParms.cbToRead.SetUInt32(0);
1718 Msg.ReqParms.fRead.SetUInt32(0);
1719
1720 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1721 if (RT_SUCCESS(rc))
1722 {
1723 rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext);
1724 if (RT_SUCCESS(rc))
1725 rc = Msg.ReqParms.uHandle.GetUInt64(phObj);
1726 if (RT_SUCCESS(rc))
1727 rc = Msg.ReqParms.cbToRead.GetUInt32(pcbToRead);
1728 if (RT_SUCCESS(rc))
1729 rc = Msg.ReqParms.fRead.GetUInt32(pfFlags);
1730 }
1731
1732 LogFlowFuncLeaveRC(rc);
1733 return rc;
1734}
1735
1736/**
1737 * Sends a request to read from a transfer object to the host.
1738 *
1739 * @returns VBox status code.
1740 * @param pCtx Shared Clipboard command context to use for the connection.
1741 * @param hObj Object handle of object to read from.
1742 * @param pvData Buffer where to store the read object data.
1743 * @param cbData Size (in bytes) of buffer.
1744 * @param pcbRead Where to store the amount (in bytes) read from the object.
1745 */
1746VBGLR3DECL(int) VbglR3ClipboardTransferObjReadSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj,
1747 void *pvData, uint32_t cbData, uint32_t *pcbRead)
1748{
1749 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1750 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1751 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1752 /* pcbRead is optional. */
1753
1754 VBoxShClObjReadWriteMsg Msg;
1755 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1756 VBOX_SHCL_GUEST_FN_OBJ_READ, VBOX_SHCL_CPARMS_OBJ_READ);
1757
1758 Msg.uContext.SetUInt64(pCtx->idContext);
1759 Msg.uHandle.SetUInt64(hObj);
1760 Msg.cbData.SetUInt32(cbData);
1761 Msg.pvData.SetPtr(pvData, cbData);
1762 Msg.cbChecksum.SetUInt32(0);
1763 Msg.pvChecksum.SetPtr(NULL, 0);
1764
1765 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1766 if (RT_SUCCESS(rc))
1767 {
1768 /** @todo Add checksum support. */
1769
1770 if (pcbRead)
1771 {
1772 rc = Msg.cbData.GetUInt32(pcbRead); AssertRC(rc);
1773 AssertReturn(cbData >= *pcbRead, VERR_TOO_MUCH_DATA);
1774 }
1775 }
1776
1777 LogFlowFuncLeaveRC(rc);
1778 return rc;
1779}
1780
1781/**
1782 * Sends a request to write to a transfer object to the host.
1783 *
1784 * @returns VBox status code.
1785 * @param pCtx Shared Clipboard command context to use for the connection.
1786 * @param hObj Object handle of object to write to.
1787 * @param pvData Buffer of data to write to object.
1788 * @param cbData Size (in bytes) of buffer.
1789 * @param pcbWritten Where to store the amount (in bytes) written to the object.
1790 */
1791VBGLR3DECL(int) VbglR3ClipboardTransferObjWriteSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj,
1792 void *pvData, uint32_t cbData, uint32_t *pcbWritten)
1793{
1794 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1795 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1796 /* cbData can be 0. */
1797 /* pcbWritten is optional. */
1798
1799 VBoxShClObjReadWriteMsg Msg;
1800 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1801 VBOX_SHCL_GUEST_FN_OBJ_WRITE, VBOX_SHCL_CPARMS_OBJ_WRITE);
1802
1803 Msg.uContext.SetUInt64(pCtx->idContext);
1804 Msg.uHandle.SetUInt64(hObj);
1805 Msg.cbData.SetUInt32(cbData);
1806 Msg.pvData.SetPtr(pvData, cbData);
1807 Msg.cbChecksum.SetUInt32(0);
1808 Msg.pvChecksum.SetPtr(NULL, 0);
1809
1810 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1811 if (RT_SUCCESS(rc))
1812 {
1813 /** @todo Add checksum support. */
1814
1815 if (pcbWritten)
1816 *pcbWritten = cbData; /** @todo For now return all as being written. */
1817 }
1818
1819 LogFlowFuncLeaveRC(rc);
1820 return rc;
1821}
1822
1823
1824/*********************************************************************************************************************************
1825* Transfer interface implementations *
1826*********************************************************************************************************************************/
1827
1828/** @copydoc SHCLTXPROVIDERIFACE::pfnRootListRead */
1829static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceRootListRead(PSHCLTXPROVIDERCTX pCtx)
1830{
1831 LogFlowFuncEnter();
1832
1833 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1834 AssertPtr(pCmdCtx);
1835
1836 int rc = VbglR3ClipboardTransferRootListRead(pCmdCtx, pCtx->pTransfer);
1837
1838 LogFlowFuncLeaveRC(rc);
1839 return rc;
1840}
1841
1842/** @copydoc SHCLTXPROVIDERIFACE::pfnListOpen */
1843static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceListOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLLISTOPENPARMS pOpenParms,
1844 PSHCLLISTHANDLE phList)
1845{
1846 LogFlowFuncEnter();
1847
1848 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1849 AssertPtr(pCmdCtx);
1850
1851 int rc = VbglR3ClipboardTransferListOpenSend(pCmdCtx, pOpenParms, phList);
1852
1853 LogFlowFuncLeaveRC(rc);
1854 return rc;
1855}
1856
1857/** @copydoc SHCLTXPROVIDERIFACE::pfnListClose */
1858static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceListClose(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList)
1859{
1860 LogFlowFuncEnter();
1861
1862 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1863 AssertPtr(pCmdCtx);
1864
1865 int rc = VbglR3ClipboardTransferListCloseSend(pCmdCtx, hList);
1866
1867 LogFlowFuncLeaveRC(rc);
1868 return rc;
1869}
1870
1871/** @copydoc SHCLTXPROVIDERIFACE::pfnListHdrRead */
1872static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceListHdrRead(PSHCLTXPROVIDERCTX pCtx,
1873 SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)
1874{
1875 LogFlowFuncEnter();
1876
1877 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1878 AssertPtr(pCmdCtx);
1879
1880 int rc = ShClTransferListHdrInit(pListHdr);
1881 if (RT_SUCCESS(rc))
1882 {
1883 if (RT_SUCCESS(rc))
1884 {
1885 rc = VbglR3ClipboardTransferListHdrRead(pCmdCtx, hList, 0 /* fFlags */, pListHdr);
1886 }
1887 else
1888 ShClTransferListHdrDestroy(pListHdr);
1889 }
1890
1891 LogFlowFuncLeaveRC(rc);
1892 return rc;
1893}
1894
1895/** @copydoc SHCLTXPROVIDERIFACE::pfnListEntryRead */
1896static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceListEntryRead(PSHCLTXPROVIDERCTX pCtx,
1897 SHCLLISTHANDLE hList, PSHCLLISTENTRY pListEntry)
1898{
1899 LogFlowFuncEnter();
1900
1901 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1902 AssertPtr(pCmdCtx);
1903
1904 int rc = VbglR3ClipboardTransferListEntryRead(pCmdCtx, hList, pListEntry);
1905
1906 LogFlowFuncLeaveRC(rc);
1907 return rc;
1908}
1909
1910/** @copydoc SHCLTXPROVIDERIFACE::pfnObjOpen */
1911static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceObjOpen(PSHCLTXPROVIDERCTX pCtx,
1912 PSHCLOBJOPENCREATEPARMS pCreateParms, PSHCLOBJHANDLE phObj)
1913{
1914 LogFlowFuncEnter();
1915
1916 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1917 AssertPtr(pCmdCtx);
1918
1919 int rc = VbglR3ClipboardTransferObjOpenSend(pCmdCtx, pCreateParms, phObj);
1920
1921 LogFlowFuncLeaveRC(rc);
1922 return rc;
1923}
1924
1925/** @copydoc SHCLTXPROVIDERIFACE::pfnObjClose */
1926static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceObjClose(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj)
1927{
1928 LogFlowFuncEnter();
1929
1930 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1931 AssertPtr(pCmdCtx);
1932
1933 int rc = VbglR3ClipboardTransferObjCloseSend(pCmdCtx, hObj);
1934
1935 LogFlowFuncLeaveRC(rc);
1936 return rc;
1937}
1938
1939/** @copydoc SHCLTXPROVIDERIFACE::pfnObjRead */
1940static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceObjRead(PSHCLTXPROVIDERCTX pCtx,
1941 SHCLOBJHANDLE hObj, void *pvData, uint32_t cbData,
1942 uint32_t fFlags, uint32_t *pcbRead)
1943{
1944 LogFlowFuncEnter();
1945
1946 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1947 AssertPtr(pCmdCtx);
1948
1949 RT_NOREF(fFlags); /* Not used yet. */
1950
1951 int rc = VbglR3ClipboardTransferObjReadSend(pCmdCtx, hObj, pvData, cbData, pcbRead);
1952
1953 LogFlowFuncLeaveRC(rc);
1954 return rc;
1955}
1956
1957/**
1958 * Creates (and registers) a transfer on the guest side.
1959 *
1960 * @returns VBox status code.
1961 * @param pCmdCtx Command context to use.
1962 * @param pTransferCtx Transfer context to init transfer for.
1963 * @param enmDir Specifies the transfer direction of this transfer.
1964 * @param enmSource Specifies the data source of the transfer.
1965 * @param idTransfer ID of transfer to create.
1966 * @param ppTransfer Where to return the transfer object on success. Optional.
1967 */
1968static int vbglR3ClipboardTransferCreate(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
1969 SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource, SHCLTRANSFERID idTransfer,
1970 PSHCLTRANSFER *ppTransfer)
1971{
1972 AssertReturn(idTransfer != NIL_SHCLTRANSFERID, VERR_WRONG_ORDER);
1973
1974 RT_NOREF(pCmdCtx);
1975
1976 PSHCLTRANSFER pTransfer;
1977 int rc = ShClTransferCreate(enmDir, enmSource, &pCmdCtx->Transfers.Callbacks, &pTransfer);
1978 if (RT_SUCCESS(rc))
1979 {
1980 rc = ShClTransferCtxRegisterById(pTransferCtx, pTransfer, idTransfer);
1981 if ( RT_SUCCESS(rc)
1982 && ppTransfer)
1983 *ppTransfer = pTransfer;
1984 }
1985
1986 if (RT_SUCCESS(rc))
1987 LogRel(("Shared Clipboard: Transfer %RU32 successfully created\n", idTransfer));
1988 else
1989 LogRel(("Shared Clipboard: Error creating transfer %RU32, rc=%Rrc\n", idTransfer, rc));
1990
1991 LogFlowFuncLeaveRC(rc);
1992 return rc;
1993}
1994
1995/**
1996 * Initializes a transfer on the guest side.
1997 *
1998 * @returns VBox status code.
1999 * @param pCmdCtx Command context to use.
2000 * @param pTransfer Transfer to init.
2001 */
2002static int vbglR3ClipboardTransferInit(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFER pTransfer)
2003{
2004 LogFlowFuncEnter();
2005
2006 SHCLTRANSFERDIR const enmDir = ShClTransferGetDir(pTransfer);
2007
2008 SHCLTXPROVIDER Provider;
2009 RT_ZERO(Provider);
2010
2011 /* Assign local provider first and overwrite interface methods below if needed. */
2012 ShClTransferProviderLocalQueryInterface(&Provider);
2013
2014 /* If this is a read transfer (reading data from host), set the interface to use
2015 * our VbglR3 routines here. */
2016 if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE) /* Host -> Guest */
2017 {
2018 Provider.Interface.pfnRootListRead = vbglR3ClipboardTransferIfaceRootListRead;
2019
2020 Provider.Interface.pfnListOpen = vbglR3ClipboardTransferIfaceListOpen;
2021 Provider.Interface.pfnListClose = vbglR3ClipboardTransferIfaceListClose;
2022 Provider.Interface.pfnListHdrRead = vbglR3ClipboardTransferIfaceListHdrRead;
2023 Provider.Interface.pfnListEntryRead = vbglR3ClipboardTransferIfaceListEntryRead;
2024
2025 Provider.Interface.pfnObjOpen = vbglR3ClipboardTransferIfaceObjOpen;
2026 Provider.Interface.pfnObjClose = vbglR3ClipboardTransferIfaceObjClose;
2027 Provider.Interface.pfnObjRead = vbglR3ClipboardTransferIfaceObjRead;
2028 }
2029 else if (enmDir == SHCLTRANSFERDIR_TO_REMOTE) /* Guest -> Host */
2030 {
2031 /* Uses the local provider assigned above. */
2032 }
2033 else
2034 AssertFailed();
2035
2036 Provider.pvUser = pCmdCtx;
2037
2038 /* Set the provider first before calling ShClTransferInit(), as the init callback might utilize some of the
2039 * provider functions. */
2040 int rc = ShClTransferSetProvider(pTransfer, &Provider);
2041 if (RT_SUCCESS(rc))
2042 {
2043 rc = ShClTransferInit(pTransfer);
2044 if (RT_SUCCESS(rc))
2045 {
2046 /* As soon as we report the INITIALIZED state to the host, the host can start reading stuff from the transfer.
2047 * So make sure that we really are ready here. */
2048 if (enmDir == SHCLTRANSFERDIR_TO_REMOTE)
2049 AssertMsgStmt(ShClTransferRootsCount(pTransfer), ("No root entries set yet!\n"
2050 "Those have to be present as soon we report the transfer as being INITIALIZED to the host\n"),
2051 rc = VERR_WRONG_ORDER);
2052 }
2053 }
2054
2055 SHCLTRANSFERID const idTransfer = ShClTransferGetID(pTransfer);
2056
2057 if (RT_SUCCESS(rc))
2058 {
2059 LogRel(("Shared Clipboard: Transfer %RU32 (%s) successfully initialized\n",
2060 idTransfer, enmDir == SHCLTRANSFERDIR_FROM_REMOTE ? "host -> guest" : "guest -> host"));
2061 }
2062 else
2063 LogRel(("Shared Clipboard: Unable to initialize transfer %RU32, rc=%Rrc\n", idTransfer, rc));
2064
2065 LogFlowFuncLeaveRC(rc);
2066 return rc;
2067}
2068
2069/**
2070 * Destroys a transfer on the guest side.
2071 *
2072 * @returns VBox status code.
2073 * @param pCmdCtx Command context to use.
2074 * @param pTransferCtx Transfer context to uninit transfer for.
2075 * @param idTransfer ID of transfer to initialize.
2076 */
2077static int vbglR3ClipboardTransferDestroy(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx, SHCLTRANSFERID idTransfer)
2078{
2079 RT_NOREF(pCmdCtx);
2080
2081 LogFlowFuncEnter();
2082
2083 int rc;
2084
2085 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx, idTransfer);
2086 if (pTransfer)
2087 {
2088 rc = ShClTransferCtxUnregisterById(pTransferCtx, idTransfer);
2089 if (RT_SUCCESS(rc))
2090 rc = ShClTransferDestroy(pTransfer);
2091
2092 if (RT_SUCCESS(rc))
2093 {
2094 LogRel(("Shared Clipboard: Transfer %RU32 successfully uninitialized\n", idTransfer));
2095 }
2096 else
2097 LogRel(("Shared Clipboard: Unable to uninitialized transfer %RU32, rc=%Rrc\n", idTransfer, rc));
2098 }
2099 else
2100 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
2101
2102 /* Send a reply in any case. */
2103 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
2104 RT_SUCCESS(rc)
2105 ? SHCLTRANSFERSTATUS_UNINITIALIZED : SHCLTRANSFERSTATUS_ERROR, rc);
2106
2107 /* The host might not have the transfer around anymore at this time, so simply ignore this error. */
2108 if (rc2 == VERR_SHCLPB_TRANSFER_ID_NOT_FOUND)
2109 rc2 = VINF_SUCCESS;
2110
2111 if (RT_SUCCESS(rc))
2112 rc = rc2;
2113
2114 LogFlowFuncLeaveRC(rc);
2115 return rc;
2116}
2117
2118/**
2119 * Requests a new host -> guest transfer from the host.
2120 *
2121 * On success this will issue an INITIALIZED status reply from the host with a transfer ID set.
2122 * This ID will be used to initialize the transfer on the guest side then.
2123 *
2124 * @returns VBox status code.
2125 * @param pCmdCtx Command context to use.
2126 */
2127VBGLR3DECL(int) VbglR3ClipboardTransferRequest(PVBGLR3SHCLCMDCTX pCmdCtx)
2128{
2129 LogFlowFuncEnter();
2130
2131 LogRel2(("Shared Clipboard: Requesting new host -> guest transfer from host\n"));
2132
2133 int rc = vbglR3ClipboardTransferStatusReplyEx(pCmdCtx, 0 /* Context ID not needed */,
2134 SHCLTRANSFERSTATUS_REQUESTED, VINF_SUCCESS);
2135 LogFlowFuncLeaveRC(rc);
2136 return rc;
2137}
2138
2139/**
2140 * Starts a transfer on the guest side.
2141 *
2142 * @returns VBox status code.
2143 * @param pCmdCtx Command context to use.
2144 * @param pTransferCtx Transfer context to start transfer for.
2145 * @param uTransferID ID to use for transfer to start.
2146 */
2147static int vbglR3ClipboardTransferStart(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
2148 SHCLTRANSFERID uTransferID)
2149{
2150 RT_NOREF(pCmdCtx);
2151
2152 LogFlowFuncEnter();
2153
2154 int rc;
2155
2156 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx, uTransferID);
2157 if (pTransfer)
2158 {
2159 rc = ShClTransferStart(pTransfer);
2160 if (RT_SUCCESS(rc))
2161 {
2162 LogRel(("Shared Clipboard: Transfer %RU32 successfully started\n", uTransferID));
2163 }
2164 else
2165 LogRel(("Shared Clipboard: Unable to start transfer %RU32, rc=%Rrc\n", uTransferID, rc));
2166 }
2167 else
2168 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
2169
2170 /* Send a reply in any case. */
2171 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
2172 RT_SUCCESS(rc)
2173 ? SHCLTRANSFERSTATUS_STARTED : SHCLTRANSFERSTATUS_ERROR, rc);
2174 if (RT_SUCCESS(rc))
2175 rc = rc2;
2176
2177 LogFlowFuncLeaveRC(rc);
2178 return rc;
2179}
2180
2181/**
2182 * Stops a transfer on the guest side.
2183 *
2184 * @returns VBox status code, or VERR_NOT_FOUND if transfer has not been found.
2185 * @param pCmdCtx Command context to use.
2186 * @param pTransferCtx Transfer context to stop transfer for.
2187 * @param uTransferID ID of transfer to stop.
2188 */
2189static int vbglR3ClipboardTransferStop(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
2190 SHCLTRANSFERID uTransferID)
2191{
2192 LogFlowFuncEnter();
2193
2194 int rc;
2195
2196 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx, uTransferID);
2197 if (pTransfer)
2198 {
2199 rc = ShClTransferCtxUnregisterById(pTransferCtx, uTransferID);
2200 if (RT_SUCCESS(rc))
2201 {
2202 LogRel(("Shared Clipboard: Transfer %RU32 successfully stopped\n", uTransferID));
2203 }
2204 else
2205 LogRel(("Shared Clipboard: Unable to stop transfer %RU32, rc=%Rrc\n", uTransferID, rc));
2206 }
2207 else
2208 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
2209
2210 /* Send a reply in any case. */
2211 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
2212 RT_SUCCESS(rc)
2213 ? SHCLTRANSFERSTATUS_STOPPED : SHCLTRANSFERSTATUS_ERROR, rc);
2214 if (RT_SUCCESS(rc))
2215 rc = rc2;
2216
2217 LogFlowFuncLeaveRC(rc);
2218 return rc;
2219}
2220
2221VBGLR3DECL(int) VbglR3ClipboardEventGetNextEx(uint32_t idMsg, uint32_t cParms,
2222 PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
2223 PVBGLR3CLIPBOARDEVENT pEvent)
2224{
2225 AssertPtrReturn(pCmdCtx, VERR_INVALID_POINTER);
2226 AssertPtrReturn(pTransferCtx, VERR_INVALID_POINTER);
2227 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
2228
2229 LogFunc(("Handling idMsg=%RU32 (%s), cParms=%RU32\n", idMsg, ShClHostMsgToStr(idMsg), cParms));
2230
2231 int rc;
2232 if (!pCmdCtx->fUseLegacyProtocol)
2233 {
2234 bool fErrorSent = false; /* Whether an error has been reported back to the host already. */
2235
2236 switch (idMsg)
2237 {
2238 case VBOX_SHCL_HOST_MSG_TRANSFER_STATUS:
2239 {
2240 SHCLTRANSFERDIR enmDir;
2241 SHCLTRANSFERREPORT transferReport;
2242 rc = VbglR3ClipboarTransferStatusRecv(pCmdCtx, &enmDir, &transferReport);
2243 if (RT_SUCCESS(rc))
2244 {
2245 const SHCLTRANSFERID idTransfer = VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext);
2246
2247 LogRel(("Shared Clipboard: Received status %s (%Rrc) for transfer %RU32\n",
2248 ShClTransferStatusToStr(transferReport.uStatus), transferReport.rc, idTransfer));
2249
2250 SHCLSOURCE enmSource = SHCLSOURCE_INVALID;
2251
2252 switch (transferReport.uStatus)
2253 {
2254 case SHCLTRANSFERSTATUS_REQUESTED: /* Only used for H->G transfers. */
2255 {
2256 enmDir = SHCLTRANSFERDIR_FROM_REMOTE;
2257 enmSource = SHCLSOURCE_REMOTE;
2258
2259 /* The host acknowledged our request to create a new transfer.
2260 * So create a new transfer here with the transfer ID we just got from the host.
2261 *
2262 * Actual initialization will be done as soon as the host sends use the INITIALIZED status for it.
2263 */
2264 PSHCLTRANSFER pTransfer;
2265 rc = vbglR3ClipboardTransferCreate(pCmdCtx, pTransferCtx, enmDir, enmSource, idTransfer, &pTransfer);
2266
2267 /* As soon as we've created our transfer locally, report back INITIALIZED to the host.
2268 * This will initialize the transfer on the host, so that in turn reports INITIALIZED
2269 * back to us (see case down below).*/
2270 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
2271 RT_SUCCESS(rc)
2272 ? SHCLTRANSFERSTATUS_INITIALIZED : SHCLTRANSFERSTATUS_ERROR, rc);
2273 if (RT_SUCCESS(rc))
2274 rc = rc2;
2275 break;
2276 }
2277
2278 case SHCLTRANSFERSTATUS_INITIALIZED:
2279 {
2280 /* The host announces the transfer direction from its point of view, so inverse the direction here. */
2281 if (enmDir == SHCLTRANSFERDIR_TO_REMOTE) /* H -> G */
2282 {
2283 enmDir = SHCLTRANSFERDIR_FROM_REMOTE;
2284 enmSource = SHCLSOURCE_REMOTE;
2285 }
2286 else if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE) /* G -> H */
2287 {
2288 enmDir = SHCLTRANSFERDIR_TO_REMOTE;
2289 enmSource = SHCLSOURCE_LOCAL;
2290 }
2291 else
2292 AssertFailedBreakStmt(rc = VERR_INVALID_PARAMETER);
2293
2294 if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE) /* H->G */
2295 {
2296 /* The host reported INITIALIZED for the transfer.
2297 * So init our local transfer as well now. */
2298 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx, idTransfer);
2299 if (pTransfer)
2300 {
2301 rc = vbglR3ClipboardTransferInit(pCmdCtx, pTransfer);
2302
2303 /* Only send back a reply on error -- we already reported INITIALIZED
2304 * in the case SHCLTRANSFERSTATUS_REQUESTED above. */
2305 if (RT_FAILURE(rc))
2306 {
2307 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
2308 SHCLTRANSFERSTATUS_ERROR, rc);
2309 AssertRC(rc2);
2310 }
2311 }
2312 else
2313 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
2314 }
2315 else if (enmDir == SHCLTRANSFERDIR_TO_REMOTE) /* G->H */
2316 {
2317 /* The host reported the INITIALIZED status together with the transfer ID.
2318 * So create a local transfer here with that ID. */
2319 PSHCLTRANSFER pTransfer;
2320 rc = vbglR3ClipboardTransferCreate(pCmdCtx, pTransferCtx, enmDir, enmSource, idTransfer, &pTransfer);
2321 if (RT_SUCCESS(rc))
2322 rc = vbglR3ClipboardTransferInit(pCmdCtx, pTransfer);
2323
2324 /* Send a reply in any case. */
2325 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
2326 RT_SUCCESS(rc)
2327 ? SHCLTRANSFERSTATUS_INITIALIZED : SHCLTRANSFERSTATUS_ERROR, rc);
2328 if (RT_SUCCESS(rc))
2329 rc = rc2;
2330 }
2331 else
2332 AssertFailedBreakStmt(rc = VERR_INVALID_PARAMETER);
2333
2334 break;
2335 }
2336
2337 case SHCLTRANSFERSTATUS_UNINITIALIZED:
2338 {
2339 rc = vbglR3ClipboardTransferDestroy(pCmdCtx, pTransferCtx, idTransfer);
2340 break;
2341 }
2342
2343 case SHCLTRANSFERSTATUS_STARTED:
2344 {
2345 rc = vbglR3ClipboardTransferStart(pCmdCtx, pTransferCtx, idTransfer);
2346 break;
2347 }
2348
2349 case SHCLTRANSFERSTATUS_STOPPED:
2350 RT_FALL_THROUGH();
2351 case SHCLTRANSFERSTATUS_CANCELED:
2352 RT_FALL_THROUGH();
2353 case SHCLTRANSFERSTATUS_KILLED:
2354 RT_FALL_THROUGH();
2355 case SHCLTRANSFERSTATUS_ERROR:
2356 {
2357 rc = vbglR3ClipboardTransferStop(pCmdCtx, pTransferCtx, idTransfer);
2358 break;
2359 }
2360
2361 default:
2362 LogRel(("Shared Clipboard: Received unknown status %#x (%Rrc) for transfer %RU32\n",
2363 transferReport.uStatus, pEvent->u.TransferStatus.Report.rc, pEvent->u.TransferStatus.uID));
2364 rc = VERR_NOT_SUPPORTED;
2365 break;
2366 }
2367
2368 if (RT_SUCCESS(rc))
2369 {
2370 pEvent->u.TransferStatus.enmDir = enmDir;
2371 pEvent->u.TransferStatus.Report = transferReport;
2372 pEvent->u.TransferStatus.uID = VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext);
2373
2374 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_TRANSFER_STATUS;
2375 }
2376 }
2377 break;
2378 }
2379
2380 case VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ:
2381 {
2382 uint32_t fRoots;
2383 rc = VbglR3ClipboardTransferRootListHdrReadReq(pCmdCtx, &fRoots);
2384
2385 /** @todo Validate / handle fRoots. */
2386
2387 if (RT_SUCCESS(rc))
2388 {
2389 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2390 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2391 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2392
2393 SHCLLISTHDR rootListHdr;
2394 ShClTransferListHdrInit(&rootListHdr);
2395
2396 rootListHdr.cEntries = ShClTransferRootsCount(pTransfer);
2397
2398 LogFlowFunc(("cRoots=%RU32\n", rootListHdr.cEntries));
2399
2400 rc = VbglR3ClipboardTransferRootListHdrReadReply(pCmdCtx, &rootListHdr);
2401 }
2402 break;
2403 }
2404
2405 case VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ:
2406 {
2407 uint64_t uIndex;
2408 uint32_t fInfo;
2409 rc = VbglR3ClipboardTransferRootListEntryReadReq(pCmdCtx, &uIndex, &fInfo);
2410 if (RT_SUCCESS(rc))
2411 {
2412 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2413 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2414 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2415
2416 PCSHCLLISTENTRY pEntry = ShClTransferRootsEntryGet(pTransfer, uIndex);
2417 if (pEntry)
2418 {
2419 rc = VbglR3ClipboardTransferRootListEntryReadReply(pCmdCtx, uIndex, pEntry);
2420 }
2421 else
2422 rc = VERR_NOT_FOUND;
2423 }
2424 break;
2425 }
2426
2427 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN:
2428 {
2429 SHCLLISTOPENPARMS openParmsList;
2430 rc = ShClTransferListOpenParmsInit(&openParmsList);
2431 if (RT_SUCCESS(rc))
2432 {
2433 rc = VbglR3ClipboardTransferListOpenRecv(pCmdCtx, &openParmsList);
2434 if (RT_SUCCESS(rc))
2435 {
2436 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2437 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2438 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2439
2440 LogFlowFunc(("pszPath=%s\n", openParmsList.pszPath));
2441
2442 SHCLLISTHANDLE hList = NIL_SHCLLISTHANDLE;
2443 rc = ShClTransferListOpen(pTransfer, &openParmsList, &hList);
2444
2445 /* Reply in any case. */
2446 int rc2 = VbglR3ClipboardTransferListOpenReply(pCmdCtx, rc, hList);
2447 AssertRC(rc2);
2448 }
2449
2450 ShClTransferListOpenParmsDestroy(&openParmsList);
2451 }
2452
2453 break;
2454 }
2455
2456 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE:
2457 {
2458 SHCLLISTHANDLE hList;
2459 rc = VbglR3ClipboardTransferListCloseRecv(pCmdCtx, &hList);
2460 if (RT_SUCCESS(rc))
2461 {
2462 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2463 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2464 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2465
2466 rc = ShClTransferListClose(pTransfer, hList);
2467
2468 /* Reply in any case. */
2469 int rc2 = VbglR3ClipboardTransferListCloseReply(pCmdCtx, rc, hList);
2470 AssertRC(rc2);
2471 }
2472
2473 break;
2474 }
2475
2476 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ:
2477 {
2478 /** @todo Handle filter + list features. */
2479
2480 SHCLLISTHANDLE hList = NIL_SHCLLISTHANDLE;
2481 uint32_t fFlags = 0;
2482 rc = VbglR3ClipboardTransferListHdrReadRecvReq(pCmdCtx, &hList, &fFlags);
2483 if (RT_SUCCESS(rc))
2484 {
2485 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2486 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2487 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2488
2489 SHCLLISTHDR hdrList;
2490 rc = ShClTransferListGetHeader(pTransfer, hList, &hdrList);
2491 if (RT_SUCCESS(rc))
2492 {
2493 rc = VbglR3ClipboardTransferListHdrWrite(pCmdCtx, hList, &hdrList);
2494
2495 ShClTransferListHdrDestroy(&hdrList);
2496 }
2497 }
2498
2499 break;
2500 }
2501
2502 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ:
2503 {
2504 LogFlowFunc(("VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ\n"));
2505
2506 SHCLLISTENTRY entryList;
2507 rc = ShClTransferListEntryInit(&entryList);
2508 if (RT_SUCCESS(rc))
2509 {
2510 SHCLLISTHANDLE hList;
2511 uint32_t fInfo;
2512 rc = VbglR3ClipboardTransferListEntryReadRecvReq(pCmdCtx, &hList, &fInfo);
2513 if (RT_SUCCESS(rc))
2514 {
2515 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2516 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2517 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2518
2519 rc = ShClTransferListRead(pTransfer, hList, &entryList);
2520 if (RT_SUCCESS(rc))
2521 {
2522 PSHCLFSOBJINFO pObjInfo = (PSHCLFSOBJINFO)entryList.pvInfo;
2523 Assert(entryList.cbInfo == sizeof(SHCLFSOBJINFO));
2524
2525 RT_NOREF(pObjInfo);
2526
2527 LogFlowFunc(("\t%s (%RU64 bytes)\n", entryList.pszName, pObjInfo->cbObject));
2528
2529 rc = VbglR3ClipboardTransferListEntryWrite(pCmdCtx, hList, &entryList);
2530 }
2531 }
2532
2533 ShClTransferListEntryDestroy(&entryList);
2534 }
2535
2536 break;
2537 }
2538
2539 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN:
2540 {
2541 SHCLOBJOPENCREATEPARMS openParms;
2542 rc = ShClTransferObjOpenParmsInit(&openParms);
2543 if (RT_SUCCESS(rc))
2544 {
2545 rc = VbglR3ClipboardTransferObjOpenRecv(pCmdCtx, &openParms);
2546 if (RT_SUCCESS(rc))
2547 {
2548 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2549 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2550 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2551
2552 SHCLOBJHANDLE hObj;
2553 rc = ShClTransferObjOpen(pTransfer, &openParms, &hObj);
2554
2555 /* Reply in any case. */
2556 int rc2 = VbglR3ClipboardTransferObjOpenReply(pCmdCtx, rc, hObj);
2557 AssertRC(rc2);
2558 }
2559
2560 ShClTransferObjOpenParmsDestroy(&openParms);
2561 }
2562
2563 break;
2564 }
2565
2566 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE:
2567 {
2568 SHCLOBJHANDLE hObj;
2569 rc = VbglR3ClipboardTransferObjCloseRecv(pCmdCtx, &hObj);
2570 if (RT_SUCCESS(rc))
2571 {
2572 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2573 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2574 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2575
2576 rc = ShClTransferObjClose(pTransfer, hObj);
2577
2578 /* Reply in any case. */
2579 int rc2 = VbglR3ClipboardTransferObjCloseReply(pCmdCtx, rc, hObj);
2580 AssertRC(rc2);
2581 }
2582
2583 break;
2584 }
2585
2586 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ:
2587 {
2588 SHCLOBJHANDLE hObj;
2589 uint32_t cbBuf;
2590 uint32_t fFlags;
2591 rc = VbglR3ClipboardTransferObjReadRecv(pCmdCtx, &hObj, &cbBuf, &fFlags);
2592 if (RT_SUCCESS(rc))
2593 {
2594 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2595 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2596 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2597
2598 AssertBreakStmt(pCmdCtx->Transfers.cbChunkSize, rc = VERR_INVALID_PARAMETER);
2599
2600 const uint32_t cbToRead = RT_MIN(cbBuf, pCmdCtx->Transfers.cbChunkSize);
2601
2602 LogFlowFunc(("hObj=%RU64, cbBuf=%RU32, fFlags=0x%x -> cbChunkSize=%RU32, cbToRead=%RU32\n",
2603 hObj, cbBuf, fFlags, pCmdCtx->Transfers.cbChunkSize, cbToRead));
2604
2605 void *pvBuf = RTMemAlloc(cbToRead);
2606 if (pvBuf)
2607 {
2608 uint32_t cbRead;
2609 rc = ShClTransferObjRead(pTransfer, hObj, pvBuf, cbToRead, fFlags, &cbRead);
2610 if (RT_SUCCESS(rc))
2611 rc = VbglR3ClipboardTransferObjWriteSend(pCmdCtx, hObj, pvBuf, cbRead, NULL /* pcbWritten */);
2612
2613 RTMemFree(pvBuf);
2614 }
2615 else
2616 rc = VERR_NO_MEMORY;
2617 }
2618
2619 break;
2620 }
2621
2622 default:
2623 {
2624 rc = VbglR3ClipboardEventGetNext(idMsg, cParms, pCmdCtx, pEvent);
2625 if (RT_FAILURE(rc))
2626 fErrorSent = true;
2627 break;
2628 }
2629 }
2630
2631 if ( !fErrorSent
2632 && RT_FAILURE(rc))
2633 {
2634 /* Report error back to the host. */
2635 int rc2 = VbglR3ClipboardWriteError(pCmdCtx->idClient, rc);
2636 AssertRC(rc2);
2637 }
2638 }
2639 else
2640 {
2641 /*
2642 * This builds on what we did in VbglR3ClipboardMsgPeekWait, so
2643 * !HACK ALERT! cParms is the format flag or flags.
2644 */
2645 rc = VINF_SUCCESS;
2646 switch (idMsg)
2647 {
2648 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
2649 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
2650 pEvent->u.fReportedFormats = cParms;
2651 break;
2652
2653 case VBOX_SHCL_HOST_MSG_READ_DATA:
2654 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2655 pEvent->u.fReadData = cParms;
2656 break;
2657
2658 case VBOX_SHCL_HOST_MSG_QUIT:
2659 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
2660 break;
2661
2662 default:
2663 AssertMsgFailed(("%u (%#x)\n", idMsg, idMsg));
2664 rc = VERR_NOT_SUPPORTED;
2665 break;
2666 }
2667 }
2668
2669 LogFlowFuncLeaveRC(rc);
2670 return rc;
2671}
2672
2673#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
2674
2675VBGLR3DECL(int) VbglR3ClipboardEventGetNext(uint32_t idMsg, uint32_t cParms, PVBGLR3SHCLCMDCTX pCtx, PVBGLR3CLIPBOARDEVENT pEvent)
2676{
2677 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
2678 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
2679
2680 RT_NOREF(cParms);
2681
2682 int rc;
2683 if (!pCtx->fUseLegacyProtocol)
2684 {
2685 LogFunc(("Handling idMsg=%RU32 (%s)\n", idMsg, ShClHostMsgToStr(idMsg)));
2686 switch (idMsg)
2687 {
2688 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
2689 {
2690 rc = vbglR3ClipboardFormatsReportRecv(pCtx, &pEvent->u.fReportedFormats);
2691 if (RT_SUCCESS(rc))
2692 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
2693 break;
2694 }
2695
2696 case VBOX_SHCL_HOST_MSG_READ_DATA_CID:
2697 {
2698 rc = vbglR3ClipboardFetchReadDataCid(pCtx, &pEvent->u.fReadData);
2699 if (RT_SUCCESS(rc))
2700 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2701 break;
2702 }
2703
2704 case VBOX_SHCL_HOST_MSG_READ_DATA:
2705 {
2706 rc = vbglR3ClipboardFetchReadData(pCtx, &pEvent->u.fReadData);
2707 if (RT_SUCCESS(rc))
2708 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2709 break;
2710 }
2711
2712 case VBOX_SHCL_HOST_MSG_QUIT:
2713 {
2714 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
2715 rc = VINF_SUCCESS;
2716 break;
2717 }
2718
2719 default:
2720 {
2721 /** @todo r=bird: BUGBUG - need a skip command here! */
2722 rc = VERR_NOT_SUPPORTED;
2723 break;
2724 }
2725 }
2726
2727 if (RT_SUCCESS(rc))
2728 {
2729 /* Copy over our command context to the event. */
2730 pEvent->cmdCtx = *pCtx;
2731 }
2732 else
2733 {
2734 /* Report error back to the host. */
2735 int rc2 = VbglR3ClipboardWriteError(pCtx->idClient, rc);
2736 AssertRC(rc2);
2737 }
2738 }
2739 else
2740 {
2741 /*
2742 * This builds on what we did in VbglR3ClipboardMsgPeekWait, so
2743 * !HACK ALERT! cParms is the format flag or flags.
2744 */
2745 rc = VINF_SUCCESS;
2746 switch (idMsg)
2747 {
2748 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
2749 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
2750 pEvent->u.fReportedFormats = cParms;
2751 break;
2752
2753 case VBOX_SHCL_HOST_MSG_READ_DATA:
2754 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2755 pEvent->u.fReadData = cParms;
2756 break;
2757
2758 case VBOX_SHCL_HOST_MSG_QUIT:
2759 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
2760 break;
2761
2762 default:
2763 AssertMsgFailed(("%u (%#x)\n", idMsg, idMsg));
2764 rc = VERR_NOT_SUPPORTED;
2765 break;
2766 }
2767 pEvent->cmdCtx = *pCtx;
2768 }
2769
2770 LogFlowFuncLeaveRC(rc);
2771 return rc;
2772}
2773
2774/**
2775 * Frees (destroys) a formerly allocated Shared Clipboard event.
2776 *
2777 * @returns IPRT status code.
2778 * @param pEvent Event to free (destroy).
2779 */
2780VBGLR3DECL(void) VbglR3ClipboardEventFree(PVBGLR3CLIPBOARDEVENT pEvent)
2781{
2782 if (!pEvent)
2783 return;
2784
2785 /* Some messages require additional cleanup. */
2786 switch (pEvent->enmType)
2787 {
2788 default:
2789 break;
2790 }
2791
2792 RTMemFree(pEvent);
2793 pEvent = NULL;
2794}
2795
2796/**
2797 * Reports (advertises) guest clipboard formats to the host.
2798 *
2799 * Legacy function, do not use anymore.
2800 *
2801 * @returns VBox status code.
2802 * @param idClient The client id returned by VbglR3ClipboardConnect().
2803 * @param fFormats The formats to report.
2804 */
2805VBGLR3DECL(int) VbglR3ClipboardReportFormats(HGCMCLIENTID idClient, uint32_t fFormats)
2806{
2807 struct
2808 {
2809 VBGLIOCHGCMCALL Hdr;
2810 VBoxShClParmReportFormats Parms;
2811 } Msg;
2812
2813 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_REPORT_FORMATS, VBOX_SHCL_CPARMS_REPORT_FORMATS);
2814 VbglHGCMParmUInt32Set(&Msg.Parms.f32Formats, fFormats);
2815
2816 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
2817
2818 LogFlowFuncLeaveRC(rc);
2819 return rc;
2820}
2821
2822/**
2823 * Sends guest clipboard data to the host.
2824 *
2825 * Legacy function kept for compatibility, do not use anymore.
2826 *
2827 * This is usually called in reply to a VBOX_SHCL_HOST_MSG_READ_DATA message
2828 * from the host.
2829 *
2830 * @returns VBox status code.
2831 * @param idClient The client id returned by VbglR3ClipboardConnect().
2832 * @param fFormat The format of the data.
2833 * @param pvData Pointer to the data to send. Can be NULL if @a cbData
2834 * is zero.
2835 * @param cbData Number of bytes of data to send. Zero is valid.
2836 */
2837VBGLR3DECL(int) VbglR3ClipboardWriteData(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb)
2838{
2839 LogFlowFuncEnter();
2840
2841 struct
2842 {
2843 VBGLIOCHGCMCALL Hdr;
2844 VBoxShClParmDataWriteOld Parms;
2845 } Msg;
2846
2847 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_DATA_WRITE, VBOX_SHCL_CPARMS_DATA_WRITE_OLD);
2848 VbglHGCMParmUInt32Set(&Msg.Parms.f32Format, fFormat);
2849 VbglHGCMParmPtrSet(&Msg.Parms.pData, pv, cb);
2850
2851 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
2852
2853 LogFlowFuncLeaveRC(rc);
2854 return rc;
2855}
2856
2857/**
2858 * Sends guest clipboard data to the host.
2859 *
2860 * This is usually called in reply to a VBOX_SHCL_HOST_MSG_READ_DATA message
2861 * from the host.
2862 *
2863 * @returns VBox status code.
2864 * @param pCtx The command context returned by VbglR3ClipboardConnectEx().
2865 * @param fFormat Clipboard format to send.
2866 * @param pvData Pointer to the data to send. Can be NULL if @a cbData
2867 * is zero.
2868 * @param cbData Number of bytes of data to send. Zero is valid.
2869 */
2870VBGLR3DECL(int) VbglR3ClipboardWriteDataEx(PVBGLR3SHCLCMDCTX pCtx, SHCLFORMAT fFormat, void *pvData, uint32_t cbData)
2871{
2872 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
2873 AssertReturn(cbData == 0 || RT_VALID_PTR(pvData), VERR_INVALID_PARAMETER);
2874
2875 LogFlowFunc(("fFormat=%#x pvData=%p cbData=%#x\n", fFormat, pvData, cbData));
2876
2877 int rc;
2878 if (pCtx->fUseLegacyProtocol)
2879 rc = VbglR3ClipboardWriteData(pCtx->idClient, fFormat, pvData, cbData);
2880 else
2881 {
2882 struct
2883 {
2884 VBGLIOCHGCMCALL Hdr;
2885 VBoxShClParmDataWrite Parms;
2886 } Msg;
2887
2888 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_DATA_WRITE, VBOX_SHCL_CPARMS_DATA_WRITE);
2889 Msg.Parms.id64Context.SetUInt64(pCtx->idContext);
2890 Msg.Parms.f32Format.SetUInt32(fFormat);
2891 Msg.Parms.pData.SetPtr(pvData, cbData);
2892
2893 LogFlowFunc(("CID=%RU32\n", pCtx->idContext));
2894
2895 rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
2896 }
2897
2898 LogFlowFuncLeaveRC(rc);
2899 return rc;
2900}
2901
2902/**
2903 * Writes an error to the host.
2904 *
2905 * @returns IPRT status code.
2906 * @param idClient The client id returned by VbglR3ClipboardConnect().
2907 * @param rcErr Error (IPRT-style) to send.
2908 */
2909VBGLR3DECL(int) VbglR3ClipboardWriteError(HGCMCLIENTID idClient, int rcErr)
2910{
2911 AssertReturn(idClient, VERR_INVALID_PARAMETER);
2912
2913 VBoxShClWriteErrorMsg Msg;
2914 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHCL_GUEST_FN_ERROR, VBOX_SHCL_CPARMS_ERROR);
2915
2916 /** @todo Context ID not used yet. */
2917 Msg.uContext.SetUInt64(0);
2918 Msg.rc.SetUInt32((uint32_t)rcErr); /* uint32_t vs. int. */
2919
2920 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
2921
2922 if (RT_FAILURE(rc))
2923 LogFlowFunc(("Sending error %Rrc failed with rc=%Rrc\n", rcErr, rc));
2924 if (rc == VERR_NOT_SUPPORTED)
2925 rc = VINF_SUCCESS;
2926
2927 if (RT_FAILURE(rc))
2928 LogRel(("Shared Clipboard: Reporting error %Rrc to the host failed with %Rrc\n", rcErr, rc));
2929
2930 LogFlowFuncLeaveRC(rc);
2931 return rc;
2932}
2933
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