VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-transfers.cpp@ 105745

Last change on this file since 105745 was 105635, checked in by vboxsync, 4 months ago

Shared Clipboard: Cleanup: Made a lot more functions static where possible and renamed the non-static ones to indicate its usage.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 86.9 KB
Line 
1/* $Id: VBoxSharedClipboardSvc-transfers.cpp 105635 2024-08-09 09:38:27Z vboxsync $ */
2/** @file
3 * Shared Clipboard Service - Internal code for transfer (list) handling.
4 */
5
6/*
7 * Copyright (C) 2019-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
33#include <VBox/log.h>
34
35#include <VBox/err.h>
36
37#include <VBox/GuestHost/clipboard-helper.h>
38#include <VBox/HostServices/VBoxClipboardSvc.h>
39#include <VBox/HostServices/VBoxClipboardExt.h>
40
41#include <VBox/AssertGuest.h>
42#include <iprt/dir.h>
43#include <iprt/file.h>
44#include <iprt/path.h>
45
46#include <VBox/GuestHost/SharedClipboard-transfers.h>
47
48#include "VBoxSharedClipboardSvc-internal.h"
49#include "VBoxSharedClipboardSvc-transfers.h"
50
51
52/*********************************************************************************************************************************
53* Externals *
54*********************************************************************************************************************************/
55extern uint32_t g_fTransferMode;
56extern SHCLEXTSTATE g_ExtState;
57extern PVBOXHGCMSVCHELPERS g_pHelpers;
58extern ClipboardClientMap g_mapClients;
59extern ClipboardClientQueue g_listClientsDeferred;
60
61
62/*********************************************************************************************************************************
63* Prototypes *
64*********************************************************************************************************************************/
65static int shClSvcTransferSendStatusAsync(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, SHCLTRANSFERSTATUS uStatus, int rcTransfer, PSHCLEVENT *ppEvent);
66static int shClSvcTransferMsgSetListOpen(uint32_t cParms, VBOXHGCMSVCPARM aParms[], uint64_t idCtx, PSHCLLISTOPENPARMS pOpenParms);
67static int shClSvcTransferMsgSetListClose(uint32_t cParms, VBOXHGCMSVCPARM aParms[], uint64_t idCtx, SHCLLISTHANDLE hList);
68
69
70/**
71 * Destroys all transfers of a Shared Clipboard client.
72 *
73 * @param pClient Client to destroy transfers for.
74 */
75void shClSvcTransferDestroyAll(PSHCLCLIENT pClient)
76{
77 if (!pClient)
78 return;
79
80 LogFlowFuncEnter();
81
82 /* Unregister and destroy all transfers.
83 * Also make sure to let the backend know that all transfers are getting destroyed.
84 *
85 * Note: The index always will be 0, as the transfer gets unregistered. */
86 PSHCLTRANSFER pTransfer;
87 while ((pTransfer = ShClTransferCtxGetTransferByIndex(&pClient->Transfers.Ctx, 0 /* Index */)))
88 ShClSvcTransferDestroy(pClient, pTransfer);
89}
90
91/**
92 * Reads a root list header from the guest, asynchronous version.
93 *
94 * @returns VBox status code.
95 * @param pClient Client to read from.
96 * @param pTransfer Transfer to read root list header for.
97 * @param ppEvent Where to return the event to wait for.
98 * Must be released by the caller with ShClEventRelease().
99 */
100int ShClSvcTransferGHRootListReadHdrAsync(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, PSHCLEVENT *ppEvent)
101{
102 LogFlowFuncEnter();
103
104 int rc;
105
106 PSHCLCLIENTMSG pMsgHdr = ShClSvcClientMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ,
107 VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ_REQ);
108 if (pMsgHdr)
109 {
110 PSHCLEVENT pEvent;
111 rc = ShClEventSourceGenerateAndRegisterEvent(&pTransfer->Events, &pEvent);
112 if (RT_SUCCESS(rc))
113 {
114 HGCMSvcSetU64(&pMsgHdr->aParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
115 ShClTransferGetID(pTransfer), pEvent->idEvent));
116 HGCMSvcSetU32(&pMsgHdr->aParms[1], 0 /* fRoots */);
117
118 ShClSvcClientLock(pClient);
119
120 ShClSvcClientMsgAdd(pClient, pMsgHdr, true /* fAppend */);
121 rc = ShClSvcClientWakeup(pClient);
122
123 ShClSvcClientUnlock(pClient);
124
125 /* Remove event from list if caller did not request event handle or in case
126 * of failure (in this case caller should not release event). */
127 if ( RT_FAILURE(rc)
128 || !ppEvent)
129 {
130 ShClEventRelease(pEvent);
131 pEvent = NULL;
132 }
133 else if (ppEvent)
134 *ppEvent = pEvent;
135 }
136 else
137 {
138 ShClSvcClientMsgFree(pClient, pMsgHdr);
139 rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
140 }
141 }
142 else
143 rc = VERR_NO_MEMORY;
144
145 LogFlowFuncLeaveRC(rc);
146 return rc;
147}
148
149/**
150 * Reads a root list header from the guest.
151 *
152 * @returns VBox status code.
153 * @param pClient Client to read from.
154 * @param pTransfer Transfer to read root list header for.
155 * @param pHdr Where to store the root list header on succeess.
156 */
157int ShClSvcTransferGHRootListReadHdr(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, PSHCLLISTHDR pHdr)
158{
159 PSHCLEVENT pEvent;
160 int rc = ShClSvcTransferGHRootListReadHdrAsync(pClient, pTransfer, &pEvent);
161 if (RT_SUCCESS(rc))
162 {
163 int rcEvent;
164 PSHCLEVENTPAYLOAD pPayload;
165 rc = ShClEventWaitEx(pEvent, pTransfer->uTimeoutMs, &rcEvent, &pPayload);
166 if (RT_SUCCESS(rc))
167 {
168 Assert(pPayload->cbData == sizeof(SHCLLISTHDR));
169
170 memcpy(pHdr, (PSHCLLISTHDR)pPayload->pvData, sizeof(SHCLLISTHDR));
171
172 LogFlowFunc(("cRoots=%RU32, fFeatures=0x%x\n", pHdr->cEntries, pHdr->fFeatures));
173
174 ShClPayloadFree(pPayload);
175 }
176 else
177 rc = rcEvent;
178
179 ShClEventRelease(pEvent);
180 pEvent = NULL;
181 }
182
183 LogFlowFuncLeaveRC(rc);
184 return rc;
185}
186
187/**
188 * Reads a root list entry from the guest, asynchronous version.
189 *
190 * @returns VBox status code.
191 * @param pClient Client to read from.
192 * @param pTransfer Transfer to read root list header for.
193 * @param idxEntry Index of entry to read.
194 * @param ppEvent Where to return the event to wait for.
195 * Must be released by the caller with ShClEventRelease().
196 */
197int ShClSvcTransferGHRootListReadEntryAsync(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, uint64_t idxEntry,
198 PSHCLEVENT *ppEvent)
199{
200 LogFlowFuncEnter();
201
202 PSHCLCLIENTMSG pMsgEntry = ShClSvcClientMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ,
203 VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ_REQ);
204 PSHCLEVENT pEvent;
205 int rc = ShClEventSourceGenerateAndRegisterEvent(&pTransfer->Events, &pEvent);
206 if (RT_SUCCESS(rc))
207 {
208 HGCMSvcSetU64(&pMsgEntry->aParms[0],
209 VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uClientID, ShClTransferGetID(pTransfer), pEvent->idEvent));
210 HGCMSvcSetU32(&pMsgEntry->aParms[1], 0 /* fFeatures */);
211 HGCMSvcSetU64(&pMsgEntry->aParms[2], idxEntry /* uIndex */);
212
213 ShClSvcClientLock(pClient);
214
215 ShClSvcClientMsgAdd(pClient, pMsgEntry, true /* fAppend */);
216 rc = ShClSvcClientWakeup(pClient);
217
218 ShClSvcClientUnlock(pClient);
219
220 /* Remove event from list if caller did not request event handle or in case
221 * of failure (in this case caller should not release event). */
222 if ( RT_FAILURE(rc)
223 || !ppEvent)
224 {
225 ShClEventRelease(pEvent);
226 pEvent = NULL;
227 }
228 else if (ppEvent)
229 *ppEvent = pEvent;
230 }
231 else
232 rc = VERR_NO_MEMORY;
233
234 LogFlowFuncLeave();
235 return rc;
236}
237
238/**
239 * Reads a root list entry from the guest.
240 *
241 * @returns VBox status code.
242 * @param pClient Client to read from.
243 * @param pTransfer Transfer to read root list header for.
244 * @param idxEntry Index of entry to read.
245 * @param ppListEntry Where to return the allocated root list entry.
246 */
247int ShClSvcTransferGHRootListReadEntry(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, uint64_t idxEntry,
248 PSHCLLISTENTRY *ppListEntry)
249{
250 AssertPtrReturn(ppListEntry, VERR_INVALID_POINTER);
251
252 PSHCLEVENT pEvent;
253 int rc = ShClSvcTransferGHRootListReadEntryAsync(pClient, pTransfer, idxEntry, &pEvent);
254 if (RT_SUCCESS(rc))
255 {
256 int rcEvent;
257 PSHCLEVENTPAYLOAD pPayload;
258 rc = ShClEventWaitEx(pEvent, pTransfer->uTimeoutMs, &rcEvent, &pPayload);
259 if (RT_SUCCESS(rc))
260 {
261 *ppListEntry = (PSHCLLISTENTRY)pPayload->pvData; /* ppLisEntry own pPayload-pvData now. */
262 }
263 else
264 rc = rcEvent;
265
266 ShClEventRelease(pEvent);
267 pEvent = NULL;
268 }
269
270 LogFlowFuncLeaveRC(rc);
271 return rc;
272}
273
274
275/*********************************************************************************************************************************
276* Provider interface implementation *
277*********************************************************************************************************************************/
278
279/** @copydoc SHCLTXPROVIDERIFACE::pfnRootListRead */
280DECLCALLBACK(int) ShClSvcTransferIfaceGHRootListRead(PSHCLTXPROVIDERCTX pCtx)
281{
282 LogFlowFuncEnter();
283
284 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
285 AssertPtr(pClient);
286
287 SHCLLISTHDR Hdr;
288 int rc = ShClSvcTransferGHRootListReadHdr(pClient, pCtx->pTransfer, &Hdr);
289 if (RT_SUCCESS(rc))
290 {
291 for (uint64_t i = 0; i < Hdr.cEntries; i++)
292 {
293 PSHCLLISTENTRY pEntry;
294 rc = ShClSvcTransferGHRootListReadEntry(pClient, pCtx->pTransfer, i, &pEntry);
295 if (RT_SUCCESS(rc))
296 rc = ShClTransferListAddEntry(&pCtx->pTransfer->lstRoots, pEntry, true /* fAppend */);
297
298 if (RT_FAILURE(rc))
299 break;
300 }
301 }
302
303 LogFlowFuncLeave();
304 return rc;
305}
306
307/** @copydoc SHCLTXPROVIDERIFACE::pfnListOpen */
308DECLCALLBACK(int) ShClSvcTransferIfaceGHListOpen(PSHCLTXPROVIDERCTX pCtx,
309 PSHCLLISTOPENPARMS pOpenParms, PSHCLLISTHANDLE phList)
310{
311 LogFlowFuncEnter();
312
313 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
314 AssertPtr(pClient);
315
316 int rc;
317
318 PSHCLCLIENTMSG pMsg = ShClSvcClientMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN,
319 VBOX_SHCL_CPARMS_LIST_OPEN);
320 if (pMsg)
321 {
322 PSHCLEVENT pEvent;
323 rc = ShClEventSourceGenerateAndRegisterEvent(&pCtx->pTransfer->Events, &pEvent);
324 if (RT_SUCCESS(rc))
325 {
326 pMsg->idCtx = VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID, pCtx->pTransfer->State.uID,
327 pEvent->idEvent);
328
329 rc = ShClTransferTransformPath(pOpenParms->pszPath, pOpenParms->cbPath);
330 if (RT_SUCCESS(rc))
331 rc = shClSvcTransferMsgSetListOpen(pMsg->cParms, pMsg->aParms, pMsg->idCtx, pOpenParms);
332 if (RT_SUCCESS(rc))
333 {
334 ShClSvcClientLock(pClient);
335
336 ShClSvcClientMsgAdd(pClient, pMsg, true /* fAppend */);
337 rc = ShClSvcClientWakeup(pClient);
338
339 ShClSvcClientUnlock(pClient);
340
341 if (RT_SUCCESS(rc))
342 {
343 int rcEvent;
344 PSHCLEVENTPAYLOAD pPayload;
345 rc = ShClEventWaitEx(pEvent, pCtx->pTransfer->uTimeoutMs, &rcEvent, &pPayload);
346 if (RT_SUCCESS(rc))
347 {
348 Assert(pPayload->cbData == sizeof(SHCLREPLY));
349
350 PSHCLREPLY pReply = (PSHCLREPLY)pPayload->pvData;
351 AssertPtr(pReply);
352
353 Assert(pReply->uType == VBOX_SHCL_TX_REPLYMSGTYPE_LIST_OPEN);
354
355 LogFlowFunc(("hList=%RU64\n", pReply->u.ListOpen.uHandle));
356
357 *phList = pReply->u.ListOpen.uHandle;
358
359 ShClPayloadFree(pPayload);
360 }
361 else
362 rc = rcEvent;
363 }
364 }
365
366 ShClEventRelease(pEvent);
367 }
368 else
369 {
370 ShClSvcClientMsgFree(pClient, pMsg);
371 rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
372 }
373 }
374 else
375 rc = VERR_NO_MEMORY;
376
377 LogFlowFuncLeaveRC(rc);
378 return rc;
379}
380
381/** @copydoc SHCLTXPROVIDERIFACE::pfnListClose */
382DECLCALLBACK(int) ShClSvcTransferIfaceGHListClose(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList)
383{
384 LogFlowFuncEnter();
385
386 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
387 AssertPtr(pClient);
388
389 int rc;
390
391 PSHCLCLIENTMSG pMsg = ShClSvcClientMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE,
392 VBOX_SHCL_CPARMS_LIST_CLOSE);
393 if (pMsg)
394 {
395 PSHCLEVENT pEvent;
396 rc = ShClEventSourceGenerateAndRegisterEvent(&pCtx->pTransfer->Events, &pEvent);
397 if (RT_SUCCESS(rc))
398 {
399 pMsg->idCtx = VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID, pCtx->pTransfer->State.uID,
400 pEvent->idEvent);
401
402 rc = shClSvcTransferMsgSetListClose(pMsg->cParms, pMsg->aParms, pMsg->idCtx, hList);
403 if (RT_SUCCESS(rc))
404 {
405 ShClSvcClientLock(pClient);
406
407 ShClSvcClientMsgAdd(pClient, pMsg, true /* fAppend */);
408 rc = ShClSvcClientWakeup(pClient);
409
410 ShClSvcClientUnlock(pClient);
411
412 if (RT_SUCCESS(rc))
413 {
414 int rcEvent;
415 PSHCLEVENTPAYLOAD pPayload;
416 rc = ShClEventWaitEx(pEvent, pCtx->pTransfer->uTimeoutMs, &rcEvent, &pPayload);
417 if (RT_SUCCESS(rc))
418 {
419 ShClPayloadFree(pPayload);
420 }
421 else
422 rc = rcEvent;
423 }
424 }
425
426 ShClEventRelease(pEvent);
427 }
428 else
429 {
430 ShClSvcClientMsgFree(pClient, pMsg);
431 rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
432 }
433 }
434 else
435 rc = VERR_NO_MEMORY;
436
437 LogFlowFuncLeaveRC(rc);
438 return rc;
439}
440
441/** @copydoc SHCLTXPROVIDERIFACE::pfnListHdrRead */
442DECLCALLBACK(int) ShClSvcTransferIfaceGHListHdrRead(PSHCLTXPROVIDERCTX pCtx,
443 SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)
444{
445 LogFlowFuncEnter();
446
447 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
448 AssertPtr(pClient);
449
450 int rc;
451
452 PSHCLCLIENTMSG pMsg = ShClSvcClientMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ,
453 VBOX_SHCL_CPARMS_LIST_HDR_READ_REQ);
454 if (pMsg)
455 {
456 PSHCLEVENT pEvent;
457 rc = ShClEventSourceGenerateAndRegisterEvent(&pCtx->pTransfer->Events, &pEvent);
458 if (RT_SUCCESS(rc))
459 {
460 HGCMSvcSetU64(&pMsg->aParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
461 pCtx->pTransfer->State.uID, pEvent->idEvent));
462 HGCMSvcSetU64(&pMsg->aParms[1], hList);
463 HGCMSvcSetU32(&pMsg->aParms[2], 0 /* fFlags */);
464
465 ShClSvcClientLock(pClient);
466
467 ShClSvcClientMsgAdd(pClient, pMsg, true /* fAppend */);
468 rc = ShClSvcClientWakeup(pClient);
469
470 ShClSvcClientUnlock(pClient);
471
472 if (RT_SUCCESS(rc))
473 {
474 int rcEvent;
475 PSHCLEVENTPAYLOAD pPayload;
476 rc = ShClEventWaitEx(pEvent, pCtx->pTransfer->uTimeoutMs, &rcEvent, &pPayload);
477 if (RT_SUCCESS(rc))
478 {
479 Assert(pPayload->cbData == sizeof(SHCLLISTHDR));
480
481 *pListHdr = *(PSHCLLISTHDR)pPayload->pvData;
482
483 ShClPayloadFree(pPayload);
484 }
485 else
486 rc = rcEvent;
487 }
488
489 ShClEventRelease(pEvent);
490 }
491 else
492 {
493 ShClSvcClientMsgFree(pClient, pMsg);
494 rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
495 }
496 }
497 else
498 rc = VERR_NO_MEMORY;
499
500 LogFlowFuncLeaveRC(rc);
501 return rc;
502}
503
504/** @copydoc SHCLTXPROVIDERIFACE::pfnListEntryRead */
505DECLCALLBACK(int) ShClSvcTransferIfaceGHListEntryRead(PSHCLTXPROVIDERCTX pCtx,
506 SHCLLISTHANDLE hList, PSHCLLISTENTRY pListEntry)
507{
508 LogFlowFuncEnter();
509
510 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
511 AssertPtr(pClient);
512
513 int rc;
514
515 PSHCLCLIENTMSG pMsg = ShClSvcClientMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ,
516 VBOX_SHCL_CPARMS_LIST_ENTRY_READ);
517 if (pMsg)
518 {
519 PSHCLEVENT pEvent;
520 rc = ShClEventSourceGenerateAndRegisterEvent(&pCtx->pTransfer->Events, &pEvent);
521 if (RT_SUCCESS(rc))
522 {
523 HGCMSvcSetU64(&pMsg->aParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
524 pCtx->pTransfer->State.uID, pEvent->idEvent));
525 HGCMSvcSetU64(&pMsg->aParms[1], hList);
526 HGCMSvcSetU32(&pMsg->aParms[2], 0 /* fInfo */);
527
528 ShClSvcClientLock(pClient);
529
530 ShClSvcClientMsgAdd(pClient, pMsg, true /* fAppend */);
531 rc = ShClSvcClientWakeup(pClient);
532
533 ShClSvcClientUnlock(pClient);
534
535 if (RT_SUCCESS(rc))
536 {
537 int rcEvent;
538 PSHCLEVENTPAYLOAD pPayload;
539 rc = ShClEventWaitEx(pEvent, pCtx->pTransfer->uTimeoutMs, &rcEvent, &pPayload);
540 if (RT_SUCCESS(rc))
541 {
542 Assert(pPayload->cbData == sizeof(SHCLLISTENTRY));
543
544 rc = ShClTransferListEntryCopy(pListEntry, (PSHCLLISTENTRY)pPayload->pvData);
545
546 ShClPayloadFree(pPayload);
547 }
548 else
549 rc = rcEvent;
550 }
551
552 ShClEventRelease(pEvent);
553 }
554 else
555 {
556 ShClSvcClientMsgFree(pClient, pMsg);
557 rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
558 }
559 }
560 else
561 rc = VERR_NO_MEMORY;
562
563 LogFlowFuncLeaveRC(rc);
564 return rc;
565}
566
567/** @copydoc SHCLTXPROVIDERIFACE::pfnObjOpen */
568DECLCALLBACK(int) ShClSvcTransferIfaceGHObjOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms, PSHCLOBJHANDLE phObj)
569{
570 LogFlowFuncEnter();
571
572 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
573 AssertPtr(pClient);
574
575 int rc;
576
577 PSHCLCLIENTMSG pMsg = ShClSvcClientMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN,
578 VBOX_SHCL_CPARMS_OBJ_OPEN);
579 if (pMsg)
580 {
581 PSHCLEVENT pEvent;
582 rc = ShClEventSourceGenerateAndRegisterEvent(&pCtx->pTransfer->Events, &pEvent);
583 if (RT_SUCCESS(rc))
584 {
585 LogFlowFunc(("pszPath=%s, fCreate=0x%x\n", pCreateParms->pszPath, pCreateParms->fCreate));
586
587 rc = ShClTransferTransformPath(pCreateParms->pszPath, pCreateParms->cbPath);
588 if (RT_SUCCESS(rc))
589 {
590 const uint32_t cbPath = (uint32_t)strlen(pCreateParms->pszPath) + 1; /* Include terminating zero */
591
592 HGCMSvcSetU64(&pMsg->aParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
593 pCtx->pTransfer->State.uID, pEvent->idEvent));
594 HGCMSvcSetU64(&pMsg->aParms[1], 0); /* uHandle */
595 HGCMSvcSetPv (&pMsg->aParms[2], pCreateParms->pszPath, cbPath);
596 HGCMSvcSetU32(&pMsg->aParms[3], pCreateParms->fCreate);
597
598 ShClSvcClientLock(pClient);
599
600 ShClSvcClientMsgAdd(pClient, pMsg, true /* fAppend */);
601 rc = ShClSvcClientWakeup(pClient);
602
603 ShClSvcClientUnlock(pClient);
604
605 if (RT_SUCCESS(rc))
606 {
607 int rcEvent;
608 PSHCLEVENTPAYLOAD pPayload;
609 rc = ShClEventWaitEx(pEvent, pCtx->pTransfer->uTimeoutMs, &rcEvent, &pPayload);
610 if (RT_SUCCESS(rc))
611 {
612 Assert(pPayload->cbData == sizeof(SHCLREPLY));
613
614 PSHCLREPLY pReply = (PSHCLREPLY)pPayload->pvData;
615 AssertPtr(pReply);
616
617 Assert(pReply->uType == VBOX_SHCL_TX_REPLYMSGTYPE_OBJ_OPEN);
618
619 LogFlowFunc(("hObj=%RU64\n", pReply->u.ObjOpen.uHandle));
620
621 *phObj = pReply->u.ObjOpen.uHandle;
622
623 ShClPayloadFree(pPayload);
624 }
625 else
626 rc = rcEvent;
627 }
628 }
629
630 ShClEventRelease(pEvent);
631 }
632 else
633 {
634 ShClSvcClientMsgFree(pClient, pMsg);
635 rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
636 }
637 }
638 else
639 rc = VERR_NO_MEMORY;
640
641 LogFlowFuncLeaveRC(rc);
642 return rc;
643}
644
645/** @copydoc SHCLTXPROVIDERIFACE::pfnObjClose */
646DECLCALLBACK(int) ShClSvcTransferIfaceGHObjClose(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj)
647{
648 LogFlowFuncEnter();
649
650 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
651 AssertPtr(pClient);
652
653 int rc;
654
655 PSHCLCLIENTMSG pMsg = ShClSvcClientMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE,
656 VBOX_SHCL_CPARMS_OBJ_CLOSE);
657 if (pMsg)
658 {
659 PSHCLEVENT pEvent;
660 rc = ShClEventSourceGenerateAndRegisterEvent(&pCtx->pTransfer->Events, &pEvent);
661 if (RT_SUCCESS(rc))
662 {
663 HGCMSvcSetU64(&pMsg->aParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
664 pCtx->pTransfer->State.uID, pEvent->idEvent));
665 HGCMSvcSetU64(&pMsg->aParms[1], hObj);
666
667 ShClSvcClientLock(pClient);
668
669 ShClSvcClientMsgAdd(pClient, pMsg, true /* fAppend */);
670 rc = ShClSvcClientWakeup(pClient);
671
672 ShClSvcClientUnlock(pClient);
673
674 if (RT_SUCCESS(rc))
675 {
676 int rcEvent;
677 PSHCLEVENTPAYLOAD pPayload;
678 rc = ShClEventWaitEx(pEvent, pCtx->pTransfer->uTimeoutMs, &rcEvent, &pPayload);
679 if (RT_SUCCESS(rc))
680 {
681 Assert(pPayload->cbData == sizeof(SHCLREPLY));
682#ifdef VBOX_STRICT
683 PSHCLREPLY pReply = (PSHCLREPLY)pPayload->pvData;
684 AssertPtr(pReply);
685
686 Assert(pReply->uType == VBOX_SHCL_TX_REPLYMSGTYPE_OBJ_CLOSE);
687
688 LogFlowFunc(("hObj=%RU64\n", pReply->u.ObjClose.uHandle));
689#endif
690 ShClPayloadFree(pPayload);
691 }
692 else
693 rc = rcEvent;
694 }
695
696 ShClEventRelease(pEvent);
697 }
698 else
699 {
700 ShClSvcClientMsgFree(pClient, pMsg);
701 rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
702 }
703 }
704 else
705 rc = VERR_NO_MEMORY;
706
707 LogFlowFuncLeaveRC(rc);
708 return rc;
709}
710
711/** @copydoc SHCLTXPROVIDERIFACE::pfnObjRead */
712DECLCALLBACK(int) ShClSvcTransferIfaceGHObjRead(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj,
713 void *pvData, uint32_t cbData, uint32_t fFlags, uint32_t *pcbRead)
714{
715 LogFlowFuncEnter();
716
717 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
718 AssertPtr(pClient);
719
720 int rc;
721
722 PSHCLCLIENTMSG pMsg = ShClSvcClientMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ,
723 VBOX_SHCL_CPARMS_OBJ_READ_REQ);
724 if (pMsg)
725 {
726 PSHCLEVENT pEvent;
727 rc = ShClEventSourceGenerateAndRegisterEvent(&pCtx->pTransfer->Events, &pEvent);
728 if (RT_SUCCESS(rc))
729 {
730 HGCMSvcSetU64(&pMsg->aParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
731 pCtx->pTransfer->State.uID, pEvent->idEvent));
732 HGCMSvcSetU64(&pMsg->aParms[1], hObj);
733 HGCMSvcSetU32(&pMsg->aParms[2], cbData);
734 HGCMSvcSetU32(&pMsg->aParms[3], fFlags);
735
736 ShClSvcClientLock(pClient);
737
738 ShClSvcClientMsgAdd(pClient, pMsg, true /* fAppend */);
739 rc = ShClSvcClientWakeup(pClient);
740
741 ShClSvcClientUnlock(pClient);
742
743 if (RT_SUCCESS(rc))
744 {
745 PSHCLEVENTPAYLOAD pPayload;
746 int rcEvent;
747 rc = ShClEventWaitEx(pEvent, pCtx->pTransfer->uTimeoutMs, &rcEvent, &pPayload);
748 if (RT_SUCCESS(rc))
749 {
750 Assert(pPayload->cbData == sizeof(SHCLOBJDATACHUNK));
751
752 PSHCLOBJDATACHUNK pDataChunk = (PSHCLOBJDATACHUNK)pPayload->pvData;
753 AssertPtr(pDataChunk);
754
755 const uint32_t cbRead = RT_MIN(cbData, pDataChunk->cbData);
756
757 memcpy(pvData, pDataChunk->pvData, cbRead);
758
759 if (pcbRead)
760 *pcbRead = cbRead;
761
762 ShClPayloadFree(pPayload);
763 }
764 else
765 rc = rcEvent;
766 }
767
768 ShClEventRelease(pEvent);
769 }
770 else
771 {
772 ShClSvcClientMsgFree(pClient, pMsg);
773 rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
774 }
775 }
776 else
777 rc = VERR_NO_MEMORY;
778
779 LogFlowFuncLeaveRC(rc);
780 return rc;
781}
782
783
784/*********************************************************************************************************************************
785* HGCM getters / setters *
786*********************************************************************************************************************************/
787
788/**
789 * Returns whether a HGCM message is allowed in a certain service mode or not.
790 *
791 * @returns \c true if message is allowed, \c false if not.
792 * @param uMode Service mode to check allowance for.
793 * @param uMsg HGCM message to check allowance for.
794 */
795bool shClSvcTransferMsgIsAllowed(uint32_t uMode, uint32_t uMsg)
796{
797 const bool fHostToGuest = uMode == VBOX_SHCL_MODE_HOST_TO_GUEST
798 || uMode == VBOX_SHCL_MODE_BIDIRECTIONAL;
799
800 const bool fGuestToHost = uMode == VBOX_SHCL_MODE_GUEST_TO_HOST
801 || uMode == VBOX_SHCL_MODE_BIDIRECTIONAL;
802
803 bool fAllowed = false; /* If in doubt, don't allow. */
804
805 switch (uMsg)
806 {
807 case VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_WRITE:
808 RT_FALL_THROUGH();
809 case VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_WRITE:
810 RT_FALL_THROUGH();
811 case VBOX_SHCL_GUEST_FN_LIST_HDR_WRITE:
812 RT_FALL_THROUGH();
813 case VBOX_SHCL_GUEST_FN_LIST_ENTRY_WRITE:
814 RT_FALL_THROUGH();
815 case VBOX_SHCL_GUEST_FN_OBJ_WRITE:
816 fAllowed = fGuestToHost;
817 break;
818
819 case VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_READ:
820 RT_FALL_THROUGH();
821 case VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_READ:
822 RT_FALL_THROUGH();
823 case VBOX_SHCL_GUEST_FN_LIST_HDR_READ:
824 RT_FALL_THROUGH();
825 case VBOX_SHCL_GUEST_FN_LIST_ENTRY_READ:
826 RT_FALL_THROUGH();
827 case VBOX_SHCL_GUEST_FN_OBJ_READ:
828 fAllowed = fHostToGuest;
829 break;
830
831 case VBOX_SHCL_GUEST_FN_CONNECT:
832 RT_FALL_THROUGH();
833 case VBOX_SHCL_GUEST_FN_NEGOTIATE_CHUNK_SIZE:
834 RT_FALL_THROUGH();
835 case VBOX_SHCL_GUEST_FN_MSG_PEEK_WAIT:
836 RT_FALL_THROUGH();
837 case VBOX_SHCL_GUEST_FN_MSG_PEEK_NOWAIT:
838 RT_FALL_THROUGH();
839 case VBOX_SHCL_GUEST_FN_REPORT_FEATURES:
840 RT_FALL_THROUGH();
841 case VBOX_SHCL_GUEST_FN_QUERY_FEATURES:
842 RT_FALL_THROUGH();
843 case VBOX_SHCL_GUEST_FN_MSG_GET:
844 RT_FALL_THROUGH();
845 case VBOX_SHCL_GUEST_FN_REPLY:
846 RT_FALL_THROUGH();
847 case VBOX_SHCL_GUEST_FN_MSG_CANCEL:
848 RT_FALL_THROUGH();
849 case VBOX_SHCL_GUEST_FN_ERROR:
850 RT_FALL_THROUGH();
851 case VBOX_SHCL_GUEST_FN_LIST_OPEN:
852 RT_FALL_THROUGH();
853 case VBOX_SHCL_GUEST_FN_LIST_CLOSE:
854 RT_FALL_THROUGH();
855 case VBOX_SHCL_GUEST_FN_OBJ_OPEN:
856 RT_FALL_THROUGH();
857 case VBOX_SHCL_GUEST_FN_OBJ_CLOSE:
858 fAllowed = fHostToGuest || fGuestToHost;
859 break;
860
861 default:
862 break;
863 }
864
865 LogFlowFunc(("uMsg=%RU32 (%s), uMode=%RU32 -> fAllowed=%RTbool\n", uMsg, ShClGuestMsgToStr(uMsg), uMode, fAllowed));
866 return fAllowed;
867}
868
869/**
870 * Gets a transfer message reply from HGCM service parameters.
871 *
872 * @returns VBox status code.
873 * @param cParms Number of HGCM parameters supplied in \a aParms.
874 * @param aParms Array of HGCM parameters.
875 * @param pReply Where to store the reply.
876 */
877static int shClSvcTransferMsgGetReply(uint32_t cParms, VBOXHGCMSVCPARM aParms[],
878 PSHCLREPLY pReply)
879{
880 int rc;
881
882 if (cParms >= VBOX_SHCL_CPARMS_REPLY_MIN)
883 {
884 /* aParms[0] has the context ID. */
885 rc = HGCMSvcGetU32(&aParms[1], &pReply->uType);
886 if (RT_SUCCESS(rc))
887 rc = HGCMSvcGetU32(&aParms[2], &pReply->rc);
888 if (RT_SUCCESS(rc))
889 rc = HGCMSvcGetPv(&aParms[3], &pReply->pvPayload, &pReply->cbPayload);
890
891 if (RT_SUCCESS(rc))
892 {
893 rc = VERR_INVALID_PARAMETER; /* Play safe. */
894
895 const unsigned idxParm = VBOX_SHCL_CPARMS_REPLY_MIN;
896
897 switch (pReply->uType)
898 {
899 case VBOX_SHCL_TX_REPLYMSGTYPE_TRANSFER_STATUS:
900 {
901 if (cParms > idxParm)
902 rc = HGCMSvcGetU32(&aParms[idxParm], &pReply->u.TransferStatus.uStatus);
903
904 LogFlowFunc(("uTransferStatus=%RU32 (%s)\n",
905 pReply->u.TransferStatus.uStatus, ShClTransferStatusToStr(pReply->u.TransferStatus.uStatus)));
906 break;
907 }
908
909 case VBOX_SHCL_TX_REPLYMSGTYPE_LIST_OPEN:
910 {
911 if (cParms > idxParm)
912 rc = HGCMSvcGetU64(&aParms[idxParm], &pReply->u.ListOpen.uHandle);
913
914 LogFlowFunc(("hListOpen=%RU64\n", pReply->u.ListOpen.uHandle));
915 break;
916 }
917
918 case VBOX_SHCL_TX_REPLYMSGTYPE_LIST_CLOSE:
919 {
920 if (cParms > idxParm)
921 rc = HGCMSvcGetU64(&aParms[idxParm], &pReply->u.ListClose.uHandle);
922
923 LogFlowFunc(("hListClose=%RU64\n", pReply->u.ListClose.uHandle));
924 break;
925 }
926
927 case VBOX_SHCL_TX_REPLYMSGTYPE_OBJ_OPEN:
928 {
929 if (cParms > idxParm)
930 rc = HGCMSvcGetU64(&aParms[idxParm], &pReply->u.ObjOpen.uHandle);
931
932 LogFlowFunc(("hObjOpen=%RU64\n", pReply->u.ObjOpen.uHandle));
933 break;
934 }
935
936 case VBOX_SHCL_TX_REPLYMSGTYPE_OBJ_CLOSE:
937 {
938 if (cParms > idxParm)
939 rc = HGCMSvcGetU64(&aParms[idxParm], &pReply->u.ObjClose.uHandle);
940
941 LogFlowFunc(("hObjClose=%RU64\n", pReply->u.ObjClose.uHandle));
942 break;
943 }
944
945 default:
946 rc = VERR_NOT_SUPPORTED;
947 break;
948 }
949 }
950 }
951 else
952 rc = VERR_INVALID_PARAMETER;
953
954 LogFlowFuncLeaveRC(rc);
955 return rc;
956}
957
958/**
959 * Gets a transfer root list header from HGCM service parameters.
960 *
961 * @returns VBox status code.
962 * @param cParms Number of HGCM parameters supplied in \a aParms.
963 * @param aParms Array of HGCM parameters.
964 * @param pRootLstHdr Where to store the transfer root list header on success.
965 */
966static int shClSvcTransferMsgGetRootListHdr(uint32_t cParms, VBOXHGCMSVCPARM aParms[],
967 PSHCLLISTHDR pRootLstHdr)
968{
969 int rc;
970
971 if (cParms == VBOX_SHCL_CPARMS_ROOT_LIST_HDR_WRITE)
972 {
973 rc = HGCMSvcGetU32(&aParms[1], &pRootLstHdr->fFeatures);
974 if (RT_SUCCESS(rc))
975 rc = HGCMSvcGetU64(&aParms[2], &pRootLstHdr->cEntries);
976 }
977 else
978 rc = VERR_INVALID_PARAMETER;
979
980 LogFlowFuncLeaveRC(rc);
981 return rc;
982}
983
984/**
985 * Gets a transfer root list entry from HGCM service parameters.
986 *
987 * @returns VBox status code.
988 * @param cParms Number of HGCM parameters supplied in \a aParms.
989 * @param aParms Array of HGCM parameters.
990 * @param pListEntry Where to store the root list entry.
991 */
992static int shClSvcTransferMsgGetRootListEntry(uint32_t cParms, VBOXHGCMSVCPARM aParms[],
993 PSHCLLISTENTRY pListEntry)
994{
995 int rc;
996
997 if (cParms == VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_WRITE)
998 {
999 rc = HGCMSvcGetU32(&aParms[1], &pListEntry->fInfo);
1000 /* Note: aParms[2] contains the entry index, currently being ignored. */
1001 if (RT_SUCCESS(rc))
1002 rc = HGCMSvcGetPv(&aParms[3], (void **)&pListEntry->pszName, &pListEntry->cbName);
1003 if (RT_SUCCESS(rc))
1004 {
1005 uint32_t cbInfo;
1006 rc = HGCMSvcGetU32(&aParms[4], &cbInfo);
1007 if (RT_SUCCESS(rc))
1008 {
1009 rc = HGCMSvcGetPv(&aParms[5], &pListEntry->pvInfo, &pListEntry->cbInfo);
1010 AssertReturn(cbInfo == pListEntry->cbInfo, VERR_INVALID_PARAMETER);
1011 }
1012 }
1013 }
1014 else
1015 rc = VERR_INVALID_PARAMETER;
1016
1017 LogFlowFuncLeaveRC(rc);
1018 return rc;
1019}
1020
1021/**
1022 * Gets a transfer list open request from HGCM service parameters.
1023 *
1024 * @returns VBox status code.
1025 * @param cParms Number of HGCM parameters supplied in \a aParms.
1026 * @param aParms Array of HGCM parameters.
1027 * @param pOpenParms Where to store the open parameters of the request.
1028 */
1029static int shClSvcTransferMsgGetListOpen(uint32_t cParms, VBOXHGCMSVCPARM aParms[],
1030 PSHCLLISTOPENPARMS pOpenParms)
1031{
1032 int rc;
1033
1034 if (cParms == VBOX_SHCL_CPARMS_LIST_OPEN)
1035 {
1036 rc = HGCMSvcGetU32(&aParms[1], &pOpenParms->fList);
1037 if (RT_SUCCESS(rc))
1038 rc = HGCMSvcGetStr(&aParms[2], &pOpenParms->pszFilter, &pOpenParms->cbFilter);
1039 if (RT_SUCCESS(rc))
1040 rc = HGCMSvcGetStr(&aParms[3], &pOpenParms->pszPath, &pOpenParms->cbPath);
1041
1042 /** @todo Some more validation. */
1043 }
1044 else
1045 rc = VERR_INVALID_PARAMETER;
1046
1047 LogFlowFuncLeaveRC(rc);
1048 return rc;
1049}
1050
1051/**
1052 * Sets a transfer list open request to HGCM service parameters.
1053 *
1054 * @returns VBox status code.
1055 * @param cParms Number of HGCM parameters supplied in \a aParms.
1056 * @param aParms Array of HGCM parameters.
1057 * @param idCtx Context ID to use.
1058 * @param pOpenParms List open parameters to set.
1059 */
1060static int shClSvcTransferMsgSetListOpen(uint32_t cParms, VBOXHGCMSVCPARM aParms[],
1061 uint64_t idCtx, PSHCLLISTOPENPARMS pOpenParms)
1062{
1063 int rc;
1064
1065 if (cParms == VBOX_SHCL_CPARMS_LIST_OPEN)
1066 {
1067 HGCMSvcSetU64(&aParms[0], idCtx);
1068 HGCMSvcSetU32(&aParms[1], pOpenParms->fList);
1069 HGCMSvcSetPv (&aParms[2], pOpenParms->pszFilter, pOpenParms->cbFilter);
1070 HGCMSvcSetPv (&aParms[3], pOpenParms->pszPath, pOpenParms->cbPath);
1071 HGCMSvcSetU64(&aParms[4], 0); /* OUT: uHandle */
1072
1073 rc = VINF_SUCCESS;
1074 }
1075 else
1076 rc = VERR_INVALID_PARAMETER;
1077
1078 LogFlowFuncLeaveRC(rc);
1079 return rc;
1080}
1081
1082/**
1083 * Sets a transfer list close request to HGCM service parameters.
1084 *
1085 * @returns VBox status code.
1086 * @param cParms Number of HGCM parameters supplied in \a aParms.
1087 * @param aParms Array of HGCM parameters.
1088 * @param idCtx Context ID to use.
1089 * @param hList Handle of list to close.
1090 */
1091static int shClSvcTransferMsgSetListClose(uint32_t cParms, VBOXHGCMSVCPARM aParms[],
1092 uint64_t idCtx, SHCLLISTHANDLE hList)
1093{
1094 int rc;
1095
1096 if (cParms == VBOX_SHCL_CPARMS_LIST_CLOSE)
1097 {
1098 HGCMSvcSetU64(&aParms[0], idCtx);
1099 HGCMSvcSetU64(&aParms[1], hList);
1100
1101 rc = VINF_SUCCESS;
1102 }
1103 else
1104 rc = VERR_INVALID_PARAMETER;
1105
1106 LogFlowFuncLeaveRC(rc);
1107 return rc;
1108}
1109
1110/**
1111 * Gets a transfer list header from HGCM service parameters.
1112 *
1113 * @returns VBox status code.
1114 * @param cParms Number of HGCM parameters supplied in \a aParms.
1115 * @param aParms Array of HGCM parameters.
1116 * @param phList Where to store the list handle.
1117 * @param pListHdr Where to store the list header.
1118 */
1119static int shClSvcTransferMsgGetListHdr(uint32_t cParms, VBOXHGCMSVCPARM aParms[],
1120 PSHCLLISTHANDLE phList, PSHCLLISTHDR pListHdr)
1121{
1122 int rc;
1123
1124 if (cParms == VBOX_SHCL_CPARMS_LIST_HDR)
1125 {
1126 rc = HGCMSvcGetU64(&aParms[1], phList);
1127 /* Note: Flags (aParms[2]) not used here. */
1128 if (RT_SUCCESS(rc))
1129 rc = HGCMSvcGetU32(&aParms[3], &pListHdr->fFeatures);
1130 if (RT_SUCCESS(rc))
1131 rc = HGCMSvcGetU64(&aParms[4], &pListHdr->cEntries);
1132 if (RT_SUCCESS(rc))
1133 rc = HGCMSvcGetU64(&aParms[5], &pListHdr->cbTotalSize);
1134
1135 if (RT_SUCCESS(rc))
1136 {
1137 /** @todo Validate pvMetaFmt + cbMetaFmt. */
1138 /** @todo Validate header checksum. */
1139 }
1140 }
1141 else
1142 rc = VERR_INVALID_PARAMETER;
1143
1144 LogFlowFuncLeaveRC(rc);
1145 return rc;
1146}
1147
1148/**
1149 * Sets a transfer list header to HGCM service parameters.
1150 *
1151 * @returns VBox status code.
1152 * @param cParms Number of HGCM parameters supplied in \a aParms.
1153 * @param aParms Array of HGCM parameters.
1154 * @param pListHdr Pointer to list header to set.
1155 */
1156static int shClSvcTransferMsgSetListHdr(uint32_t cParms, VBOXHGCMSVCPARM aParms[], PSHCLLISTHDR pListHdr)
1157{
1158 int rc;
1159
1160 if (cParms == VBOX_SHCL_CPARMS_LIST_HDR)
1161 {
1162 /** @todo Set pvMetaFmt + cbMetaFmt. */
1163 /** @todo Calculate header checksum. */
1164
1165 HGCMSvcSetU32(&aParms[3], pListHdr->fFeatures);
1166 HGCMSvcSetU64(&aParms[4], pListHdr->cEntries);
1167 HGCMSvcSetU64(&aParms[5], pListHdr->cbTotalSize);
1168
1169 rc = VINF_SUCCESS;
1170 }
1171 else
1172 rc = VERR_INVALID_PARAMETER;
1173
1174 LogFlowFuncLeaveRC(rc);
1175 return rc;
1176}
1177
1178/**
1179 * Gets a transfer list entry from HGCM service parameters.
1180 *
1181 * @returns VBox status code.
1182 * @param cParms Number of HGCM parameters supplied in \a aParms.
1183 * @param aParms Array of HGCM parameters.
1184 * @param phList Where to store the list handle.
1185 * @param pListEntry Where to store the list entry.
1186 */
1187static int shClSvcTransferMsgGetListEntry(uint32_t cParms, VBOXHGCMSVCPARM aParms[],
1188 PSHCLLISTHANDLE phList, PSHCLLISTENTRY pListEntry)
1189{
1190 int rc;
1191
1192 if (cParms == VBOX_SHCL_CPARMS_LIST_ENTRY)
1193 {
1194 rc = HGCMSvcGetU64(&aParms[1], phList);
1195 if (RT_SUCCESS(rc))
1196 rc = HGCMSvcGetU32(&aParms[2], &pListEntry->fInfo);
1197 if (RT_SUCCESS(rc))
1198 rc = HGCMSvcGetPv(&aParms[3], (void **)&pListEntry->pszName, &pListEntry->cbName);
1199 if (RT_SUCCESS(rc))
1200 {
1201 uint32_t cbInfo;
1202 rc = HGCMSvcGetU32(&aParms[4], &cbInfo);
1203 if (RT_SUCCESS(rc))
1204 {
1205 rc = HGCMSvcGetPv(&aParms[5], &pListEntry->pvInfo, &pListEntry->cbInfo);
1206 AssertReturn(cbInfo == pListEntry->cbInfo, VERR_INVALID_PARAMETER);
1207 }
1208 }
1209
1210 if (RT_SUCCESS(rc))
1211 {
1212 if (!ShClTransferListEntryIsValid(pListEntry))
1213 rc = VERR_INVALID_PARAMETER;
1214 }
1215 }
1216 else
1217 rc = VERR_INVALID_PARAMETER;
1218
1219 LogFlowFuncLeaveRC(rc);
1220 return rc;
1221}
1222
1223/**
1224 * Sets a Shared Clipboard list entry to HGCM service parameters.
1225 *
1226 * @returns VBox status code.
1227 * @param cParms Number of HGCM parameters supplied in \a aParms.
1228 * @param aParms Array of HGCM parameters.
1229 * @param pEntry Pointer list entry to set.
1230 */
1231static int shClSvcTransferMsgSetListEntry(uint32_t cParms, VBOXHGCMSVCPARM aParms[],
1232 PSHCLLISTENTRY pEntry)
1233{
1234 int rc;
1235
1236 /* Sanity. */
1237 AssertReturn(ShClTransferListEntryIsValid(pEntry), VERR_INVALID_PARAMETER);
1238
1239 if (cParms == VBOX_SHCL_CPARMS_LIST_ENTRY)
1240 {
1241 /* Entry name */
1242 void *pvDst = aParms[3].u.pointer.addr;
1243 size_t cbDst = aParms[3].u.pointer.size;
1244 memcpy(pvDst, pEntry->pszName, RT_MIN(pEntry->cbName, cbDst));
1245
1246 /* Info size */
1247 HGCMSvcSetU32(&aParms[4], pEntry->cbInfo);
1248
1249 /* Info data */
1250 pvDst = aParms[5].u.pointer.addr;
1251 cbDst = aParms[5].u.pointer.size;
1252 memcpy(pvDst, pEntry->pvInfo, RT_MIN(pEntry->cbInfo, cbDst));
1253
1254 rc = VINF_SUCCESS;
1255 }
1256 else
1257 rc = VERR_INVALID_PARAMETER;
1258
1259 LogFlowFuncLeaveRC(rc);
1260 return rc;
1261}
1262
1263/**
1264 * Gets a transfer object data chunk from HGCM service parameters.
1265 *
1266 * @returns VBox status code.
1267 * @param cParms Number of HGCM parameters supplied in \a aParms.
1268 * @param aParms Array of HGCM parameters.
1269 * @param pDataChunk Where to store the object data chunk data.
1270 */
1271static int shClSvcTransferGetObjDataChunk(uint32_t cParms, VBOXHGCMSVCPARM aParms[], PSHCLOBJDATACHUNK pDataChunk)
1272{
1273 AssertPtrReturn(aParms, VERR_INVALID_PARAMETER);
1274 AssertPtrReturn(pDataChunk, VERR_INVALID_PARAMETER);
1275
1276 int rc;
1277
1278 if (cParms == VBOX_SHCL_CPARMS_OBJ_WRITE)
1279 {
1280 rc = HGCMSvcGetU64(&aParms[1], &pDataChunk->uHandle);
1281 if (RT_SUCCESS(rc))
1282 {
1283 uint32_t cbToRead;
1284 rc = HGCMSvcGetU32(&aParms[2], &cbToRead);
1285 if (RT_SUCCESS(rc))
1286 {
1287 rc = HGCMSvcGetPv(&aParms[3], &pDataChunk->pvData, &pDataChunk->cbData);
1288 if (RT_SUCCESS(rc))
1289 rc = cbToRead == pDataChunk->cbData ? VINF_SUCCESS : VERR_INVALID_PARAMETER;
1290 }
1291
1292 /** @todo Implement checksum handling. */
1293 }
1294 }
1295 else
1296 rc = VERR_INVALID_PARAMETER;
1297
1298 LogFlowFuncLeaveRC(rc);
1299 return rc;
1300}
1301
1302/**
1303 * Handles a guest reply (VBOX_SHCL_GUEST_FN_REPLY) message.
1304 *
1305 * @returns VBox status code.
1306 * @param pClient Pointer to associated client.
1307 * @param pTransfer Transfer to handle reply for.
1308 * @param cParms Number of function parameters supplied.
1309 * @param aParms Array function parameters supplied.
1310 */
1311static int shClSvcTransferMsgHandleReply(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, uint32_t cParms, VBOXHGCMSVCPARM aParms[])
1312{
1313 LogFlowFunc(("pTransfer=%p\n", pTransfer));
1314
1315 int rc;
1316
1317 uint32_t cbReply = sizeof(SHCLREPLY);
1318 PSHCLREPLY pReply = (PSHCLREPLY)RTMemAlloc(cbReply);
1319 if (pReply)
1320 {
1321 rc = shClSvcTransferMsgGetReply(cParms, aParms, pReply);
1322 if (RT_SUCCESS(rc))
1323 {
1324 if ( pReply->uType == VBOX_SHCL_TX_REPLYMSGTYPE_TRANSFER_STATUS
1325 && pReply->u.TransferStatus.uStatus == SHCLTRANSFERSTATUS_REQUESTED)
1326 {
1327 /* SHCLTRANSFERSTATUS_REQUESTED is special, as it doesn't provide a transfer. */
1328 }
1329 else /* Everything else needs a valid transfer ID. */
1330 {
1331 if (!pTransfer)
1332 {
1333 LogRel2(("Shared Clipboard: Guest didn't specify a (valid) transfer\n"));
1334 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
1335 }
1336 }
1337
1338 if (RT_FAILURE(rc))
1339 {
1340 RTMemFree(pReply);
1341 pReply = NULL;
1342
1343 return rc;
1344 }
1345
1346 PSHCLEVENTPAYLOAD pPayload
1347 = (PSHCLEVENTPAYLOAD)RTMemAlloc(sizeof(SHCLEVENTPAYLOAD));
1348 if (pPayload)
1349 {
1350 pPayload->pvData = pReply;
1351 pPayload->cbData = cbReply;
1352
1353 SHCLTRANSFERID const idTransfer = pTransfer ? ShClTransferGetID(pTransfer) : NIL_SHCLTRANSFERID;
1354
1355 switch (pReply->uType)
1356 {
1357 case VBOX_SHCL_TX_REPLYMSGTYPE_TRANSFER_STATUS:
1358 {
1359 LogRel2(("Shared Clipboard: Guest reported status %s for transfer %RU16\n",
1360 ShClTransferStatusToStr(pReply->u.TransferStatus.uStatus), idTransfer));
1361
1362 /* SHCLTRANSFERSTATUS_REQUESTED is special, as it doesn't provide a transfer ID. */
1363 if (SHCLTRANSFERSTATUS_REQUESTED == pReply->u.TransferStatus.uStatus)
1364 {
1365 LogRel2(("Shared Clipboard: Guest requested a new host -> guest transfer\n"));
1366 }
1367
1368 switch (pReply->u.TransferStatus.uStatus)
1369 {
1370 case SHCLTRANSFERSTATUS_REQUESTED: /* Guest requests a H->G transfer. */
1371 {
1372 uint32_t const uMode = ShClSvcGetMode();
1373 if ( uMode == VBOX_SHCL_MODE_HOST_TO_GUEST
1374 || uMode == VBOX_SHCL_MODE_BIDIRECTIONAL)
1375 {
1376 /* We only create (but not initialize) the transfer here. This is the most lightweight form of
1377 * having a pending transfer around. Report back the new transfer ID to the guest then. */
1378 if (pTransfer == NULL) /* Must not exist yet. */
1379 {
1380 rc = ShClSvcTransferCreate(pClient, SHCLTRANSFERDIR_TO_REMOTE, SHCLSOURCE_LOCAL,
1381 NIL_SHCLTRANSFERID /* Creates a new transfer ID */,
1382 &pTransfer);
1383 if (RT_SUCCESS(rc))
1384 {
1385 ShClSvcClientLock(pClient);
1386
1387 rc = shClSvcTransferSendStatusAsync(pClient, pTransfer,
1388 SHCLTRANSFERSTATUS_REQUESTED, VINF_SUCCESS,
1389 NULL);
1390 ShClSvcClientUnlock(pClient);
1391 }
1392 }
1393 else
1394 rc = VERR_WRONG_ORDER;
1395 }
1396 else
1397 rc = VERR_INVALID_PARAMETER;
1398
1399 break;
1400 }
1401
1402 case SHCLTRANSFERSTATUS_INITIALIZED: /* Guest reports the transfer as being initialized. */
1403 {
1404 switch (ShClTransferGetDir(pTransfer))
1405 {
1406 case SHCLTRANSFERDIR_FROM_REMOTE: /* G->H */
1407 /* Already done locally when creating the transfer. */
1408 break;
1409
1410 case SHCLTRANSFERDIR_TO_REMOTE: /* H->G */
1411 {
1412 /* Initialize the transfer on the host side. */
1413 rc = ShClSvcTransferInit(pClient, pTransfer);
1414 break;
1415 }
1416
1417 default:
1418 AssertFailed();
1419 break;
1420 }
1421
1422 break;
1423 }
1424 case SHCLTRANSFERSTATUS_STARTED: /* Guest has started the transfer on its side. */
1425 {
1426 /* We only need to start for H->G transfers here.
1427 * For G->H transfers we start this as soon as the host clipboard requests data. */
1428 if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_TO_REMOTE)
1429 {
1430 /* Start the transfer on the host side. */
1431 rc = ShClSvcTransferStart(pClient, pTransfer);
1432 }
1433 break;
1434 }
1435
1436 case SHCLTRANSFERSTATUS_CANCELED:
1437 RT_FALL_THROUGH();
1438 case SHCLTRANSFERSTATUS_KILLED:
1439 {
1440 LogRel2(("Shared Clipboard: Guest has %s transfer %RU16\n",
1441 pReply->u.TransferStatus.uStatus == SHCLTRANSFERSTATUS_CANCELED ? "canceled" : "killed", idTransfer));
1442
1443 switch (pReply->u.TransferStatus.uStatus)
1444 {
1445 case SHCLTRANSFERSTATUS_CANCELED:
1446 rc = ShClTransferCancel(pTransfer);
1447 break;
1448
1449 case SHCLTRANSFERSTATUS_KILLED:
1450 rc = ShClTransferKill(pTransfer);
1451 break;
1452
1453 default:
1454 AssertFailed();
1455 break;
1456 }
1457
1458 break;
1459 }
1460
1461 case SHCLTRANSFERSTATUS_COMPLETED:
1462 {
1463 LogRel2(("Shared Clipboard: Guest has completed transfer %RU16\n", idTransfer));
1464
1465 rc = ShClTransferComplete(pTransfer);
1466 break;
1467 }
1468
1469 case SHCLTRANSFERSTATUS_ERROR:
1470 {
1471 LogRelMax(64, ("Shared Clipboard: Guest reported error %Rrc for transfer %RU16\n",
1472 pReply->rc, pTransfer->State.uID));
1473
1474 if (g_ExtState.pfnExtension)
1475 {
1476 SHCLEXTPARMS parms;
1477 RT_ZERO(parms);
1478
1479 parms.u.Error.rc = pReply->rc;
1480 parms.u.Error.pszMsg = RTStrAPrintf2("Guest reported error %Rrc for transfer %RU16", /** @todo Make the error messages more fine-grained based on rc. */
1481 pReply->rc, pTransfer->State.uID);
1482 AssertPtrBreakStmt(parms.u.Error.pszMsg, rc = VERR_NO_MEMORY);
1483
1484 g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_ERROR, &parms, sizeof(parms));
1485
1486 RTStrFree(parms.u.Error.pszMsg);
1487 parms.u.Error.pszMsg = NULL;
1488 }
1489
1490 rc = ShClTransferError(pTransfer, pReply->rc);
1491 break;
1492 }
1493
1494 default:
1495 {
1496 LogRelMax(64, ("Shared Clipboard: Unknown transfer status %#x from guest received\n",
1497 pReply->u.TransferStatus.uStatus));
1498 rc = VERR_INVALID_PARAMETER;
1499 break;
1500 }
1501 }
1502
1503 /* Tell the backend. */
1504 int rc2 = ShClBackendTransferHandleStatusReply(pClient->pBackend, pClient, pTransfer,
1505 SHCLSOURCE_REMOTE,
1506 pReply->u.TransferStatus.uStatus, pReply->rc);
1507 if (RT_SUCCESS(rc))
1508 rc = rc2;
1509
1510 RT_FALL_THROUGH(); /* Make sure to also signal any waiters by using the block down below. */
1511 }
1512 case VBOX_SHCL_TX_REPLYMSGTYPE_LIST_OPEN:
1513 RT_FALL_THROUGH();
1514 case VBOX_SHCL_TX_REPLYMSGTYPE_LIST_CLOSE:
1515 RT_FALL_THROUGH();
1516 case VBOX_SHCL_TX_REPLYMSGTYPE_OBJ_OPEN:
1517 RT_FALL_THROUGH();
1518 case VBOX_SHCL_TX_REPLYMSGTYPE_OBJ_CLOSE:
1519 {
1520 uint64_t uCID;
1521 rc = HGCMSvcGetU64(&aParms[0], &uCID);
1522 if (RT_SUCCESS(rc))
1523 {
1524 const PSHCLEVENT pEvent
1525 = ShClEventSourceGetFromId(&pTransfer->Events, VBOX_SHCL_CONTEXTID_GET_EVENT(uCID));
1526 if (pEvent)
1527 {
1528 LogFlowFunc(("uCID=%RU64 -> idEvent=%RU32, rcReply=%Rrc\n", uCID, pEvent->idEvent, pReply->rc));
1529
1530 rc = ShClEventSignalEx(pEvent, pReply->rc, pPayload);
1531 }
1532 }
1533 break;
1534 }
1535
1536 default:
1537 LogRelMax(64, ("Shared Clipboard: Unknown reply type %#x from guest received\n", pReply->uType));
1538 ShClTransferCancel(pTransfer); /* Avoid clogging up the transfer list. */
1539 rc = VERR_INVALID_PARAMETER;
1540 break;
1541 }
1542
1543 if ( ShClTransferIsAborted(pTransfer)
1544 || ShClTransferIsComplete(pTransfer))
1545 {
1546 ShClSvcTransferDestroy(pClient, pTransfer);
1547 pTransfer = NULL;
1548 }
1549
1550 if (RT_FAILURE(rc))
1551 {
1552 if (pPayload)
1553 RTMemFree(pPayload);
1554 }
1555 }
1556 else
1557 rc = VERR_NO_MEMORY;
1558 }
1559 }
1560 else
1561 rc = VERR_NO_MEMORY;
1562
1563 if (RT_FAILURE(rc))
1564 {
1565 if (pReply)
1566 RTMemFree(pReply);
1567 }
1568
1569 LogFlowFuncLeaveRC(rc);
1570 return rc;
1571}
1572
1573/**
1574 * Transfer message client (guest) handler for the Shared Clipboard host service.
1575 *
1576 * @returns VBox status code, or VINF_HGCM_ASYNC_EXECUTE if returning to the client will be deferred.
1577 * @param pClient Pointer to associated client.
1578 * @param callHandle The client's call handle of this call.
1579 * @param u32Function Function number being called.
1580 * @param cParms Number of function parameters supplied.
1581 * @param aParms Array function parameters supplied.
1582 * @param tsArrival Timestamp of arrival.
1583 */
1584int ShClSvcTransferMsgClientHandler(PSHCLCLIENT pClient,
1585 VBOXHGCMCALLHANDLE callHandle,
1586 uint32_t u32Function,
1587 uint32_t cParms,
1588 VBOXHGCMSVCPARM aParms[],
1589 uint64_t tsArrival)
1590{
1591 RT_NOREF(callHandle, aParms, tsArrival);
1592
1593 LogFlowFunc(("uClient=%RU32, u32Function=%RU32 (%s), cParms=%RU32, g_ExtState.pfnExtension=%p\n",
1594 pClient->State.uClientID, u32Function, ShClGuestMsgToStr(u32Function), cParms, g_ExtState.pfnExtension));
1595
1596 /* Check if we've the right mode set. */
1597 if (!shClSvcTransferMsgIsAllowed(ShClSvcGetMode(), u32Function))
1598 {
1599 LogFunc(("Wrong clipboard mode, denying access\n"));
1600 return VERR_ACCESS_DENIED;
1601 }
1602
1603 int rc = VERR_INVALID_PARAMETER; /* Play safe by default. */
1604
1605 if (cParms < 1)
1606 return rc;
1607 ASSERT_GUEST_RETURN(aParms[0].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE);
1608
1609 uint64_t uCID = 0; /* Context ID */
1610 rc = HGCMSvcGetU64(&aParms[0], &uCID);
1611 if (RT_FAILURE(rc))
1612 return rc;
1613
1614 /*
1615 * Pre-check: For certain messages we need to make sure that a (right) transfer is present.
1616 */
1617 const SHCLTRANSFERID idTransfer = VBOX_SHCL_CONTEXTID_GET_TRANSFER(uCID);
1618 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(&pClient->Transfers.Ctx, idTransfer);
1619
1620 rc = VERR_INVALID_PARAMETER; /* Play safe. */
1621
1622 switch (u32Function)
1623 {
1624 case VBOX_SHCL_GUEST_FN_REPLY:
1625 {
1626 rc = shClSvcTransferMsgHandleReply(pClient, pTransfer, cParms, aParms);
1627 break;
1628 }
1629
1630 case VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_READ:
1631 {
1632 if (cParms != VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ)
1633 break;
1634
1635 ASSERT_GUEST_RETURN(aParms[1].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE); /* Features */
1636 ASSERT_GUEST_RETURN(aParms[2].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE); /* # Entries */
1637
1638 SHCLLISTHDR rootListHdr;
1639 RT_ZERO(rootListHdr);
1640
1641 rootListHdr.cEntries = ShClTransferRootsCount(pTransfer);
1642 /** @todo BUGBUG What about the features? */
1643
1644 HGCMSvcSetU64(&aParms[0], 0 /* Context ID */);
1645 HGCMSvcSetU32(&aParms[1], rootListHdr.fFeatures);
1646 HGCMSvcSetU64(&aParms[2], rootListHdr.cEntries);
1647
1648 rc = VINF_SUCCESS;
1649 break;
1650 }
1651
1652 case VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_WRITE:
1653 {
1654 SHCLLISTHDR lstHdr;
1655 rc = shClSvcTransferMsgGetRootListHdr(cParms, aParms, &lstHdr);
1656 if (RT_SUCCESS(rc))
1657 {
1658 void *pvData = ShClTransferListHdrDup(&lstHdr);
1659 uint32_t cbData = sizeof(SHCLLISTHDR);
1660
1661 const PSHCLEVENT pEvent = ShClEventSourceGetFromId(&pTransfer->Events, VBOX_SHCL_CONTEXTID_GET_EVENT(uCID));
1662 if (pEvent)
1663 {
1664 PSHCLEVENTPAYLOAD pPayload;
1665 rc = ShClPayloadAlloc(pEvent->idEvent, pvData, cbData, &pPayload);
1666 if (RT_SUCCESS(rc))
1667 {
1668 rc = ShClEventSignal(pEvent, pPayload);
1669 if (RT_FAILURE(rc))
1670 ShClPayloadFree(pPayload);
1671 }
1672 }
1673 else
1674 rc = VERR_SHCLPB_EVENT_ID_NOT_FOUND;
1675 }
1676 break;
1677 }
1678
1679 case VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_READ:
1680 {
1681 if (cParms != VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ)
1682 break;
1683
1684 ASSERT_GUEST_RETURN(aParms[1].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE); /* Info flags */
1685 ASSERT_GUEST_RETURN(aParms[2].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE); /* Entry index # */
1686 ASSERT_GUEST_RETURN(aParms[3].type == VBOX_HGCM_SVC_PARM_PTR, VERR_WRONG_PARAMETER_TYPE); /* Entry name */
1687 ASSERT_GUEST_RETURN(aParms[4].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE); /* Info size */
1688 ASSERT_GUEST_RETURN(aParms[5].type == VBOX_HGCM_SVC_PARM_PTR, VERR_WRONG_PARAMETER_TYPE); /* Info data */
1689
1690 uint32_t fInfo;
1691 rc = HGCMSvcGetU32(&aParms[1], &fInfo);
1692 AssertRCBreak(rc);
1693
1694 ASSERT_GUEST_RETURN(fInfo & VBOX_SHCL_INFO_F_FSOBJINFO, VERR_WRONG_PARAMETER_TYPE); /* Validate info flags. */
1695
1696 uint64_t uIdx;
1697 rc = HGCMSvcGetU64(&aParms[2], &uIdx);
1698 AssertRCBreak(rc);
1699
1700 PCSHCLLISTENTRY pEntry = ShClTransferRootsEntryGet(pTransfer, uIdx);
1701 if (pEntry)
1702 {
1703 /* Entry name */
1704 void *pvDst = aParms[3].u.pointer.addr;
1705 size_t cbDst = aParms[3].u.pointer.size;
1706 memcpy(pvDst, pEntry->pszName, RT_MIN(pEntry->cbName, cbDst));
1707
1708 /* Info size */
1709 HGCMSvcSetU32(&aParms[4], pEntry->cbInfo);
1710
1711 /* Info data */
1712 pvDst = aParms[5].u.pointer.addr;
1713 cbDst = aParms[5].u.pointer.size;
1714 memcpy(pvDst, pEntry->pvInfo, RT_MIN(pEntry->cbInfo, cbDst));
1715 }
1716 else
1717 rc = VERR_NOT_FOUND;
1718
1719 break;
1720 }
1721
1722 case VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_WRITE:
1723 {
1724 SHCLLISTENTRY lstEntry;
1725 rc = shClSvcTransferMsgGetRootListEntry(cParms, aParms, &lstEntry);
1726 if (RT_SUCCESS(rc))
1727 {
1728 void *pvData = ShClTransferListEntryDup(&lstEntry);
1729 uint32_t cbData = sizeof(SHCLLISTENTRY);
1730
1731 const PSHCLEVENT pEvent = ShClEventSourceGetFromId(&pTransfer->Events, VBOX_SHCL_CONTEXTID_GET_EVENT(uCID));
1732 if (pEvent)
1733 {
1734 PSHCLEVENTPAYLOAD pPayload;
1735 rc = ShClPayloadAlloc(pEvent->idEvent, pvData, cbData, &pPayload);
1736 if (RT_SUCCESS(rc))
1737 {
1738 rc = ShClEventSignal(pEvent, pPayload);
1739 if (RT_FAILURE(rc))
1740 ShClPayloadFree(pPayload);
1741 }
1742 }
1743 else
1744 rc = VERR_SHCLPB_EVENT_ID_NOT_FOUND;
1745 }
1746 break;
1747 }
1748
1749 case VBOX_SHCL_GUEST_FN_LIST_OPEN:
1750 {
1751 if (cParms != VBOX_SHCL_CPARMS_LIST_OPEN)
1752 break;
1753
1754 SHCLLISTOPENPARMS listOpenParms;
1755 rc = shClSvcTransferMsgGetListOpen(cParms, aParms, &listOpenParms);
1756 if (RT_SUCCESS(rc))
1757 {
1758 SHCLLISTHANDLE hList;
1759 rc = ShClTransferListOpen(pTransfer, &listOpenParms, &hList);
1760 if (RT_SUCCESS(rc))
1761 {
1762 /* Return list handle. */
1763 HGCMSvcSetU64(&aParms[4], hList);
1764 }
1765 }
1766 break;
1767 }
1768
1769 case VBOX_SHCL_GUEST_FN_LIST_CLOSE:
1770 {
1771 if (cParms != VBOX_SHCL_CPARMS_LIST_CLOSE)
1772 break;
1773
1774 SHCLLISTHANDLE hList;
1775 rc = HGCMSvcGetU64(&aParms[1], &hList);
1776 if (RT_SUCCESS(rc))
1777 {
1778 rc = ShClTransferListClose(pTransfer, hList);
1779 }
1780 break;
1781 }
1782
1783 case VBOX_SHCL_GUEST_FN_LIST_HDR_READ:
1784 {
1785 if (cParms != VBOX_SHCL_CPARMS_LIST_HDR)
1786 break;
1787
1788 SHCLLISTHANDLE hList;
1789 rc = HGCMSvcGetU64(&aParms[1], &hList); /* Get list handle. */
1790 if (RT_SUCCESS(rc))
1791 {
1792 SHCLLISTHDR hdrList;
1793 rc = ShClTransferListGetHeader(pTransfer, hList, &hdrList);
1794 if (RT_SUCCESS(rc))
1795 rc = shClSvcTransferMsgSetListHdr(cParms, aParms, &hdrList);
1796 }
1797 break;
1798 }
1799
1800 case VBOX_SHCL_GUEST_FN_LIST_HDR_WRITE:
1801 {
1802 SHCLLISTHDR hdrList;
1803 rc = ShClTransferListHdrInit(&hdrList);
1804 if (RT_SUCCESS(rc))
1805 {
1806 SHCLLISTHANDLE hList;
1807 rc = shClSvcTransferMsgGetListHdr(cParms, aParms, &hList, &hdrList);
1808 if (RT_SUCCESS(rc))
1809 {
1810 void *pvData = ShClTransferListHdrDup(&hdrList);
1811 uint32_t cbData = sizeof(SHCLLISTHDR);
1812
1813 const PSHCLEVENT pEvent = ShClEventSourceGetFromId(&pTransfer->Events, VBOX_SHCL_CONTEXTID_GET_EVENT(uCID));
1814 if (pEvent)
1815 {
1816 PSHCLEVENTPAYLOAD pPayload;
1817 rc = ShClPayloadAlloc(pEvent->idEvent, pvData, cbData, &pPayload);
1818 if (RT_SUCCESS(rc))
1819 {
1820 rc = ShClEventSignal(pEvent, pPayload);
1821 if (RT_FAILURE(rc))
1822 ShClPayloadFree(pPayload);
1823 }
1824 }
1825 else
1826 rc = VERR_SHCLPB_EVENT_ID_NOT_FOUND;
1827 }
1828 }
1829 break;
1830 }
1831
1832 case VBOX_SHCL_GUEST_FN_LIST_ENTRY_READ:
1833 {
1834 if (cParms != VBOX_SHCL_CPARMS_LIST_ENTRY)
1835 break;
1836
1837 SHCLLISTHANDLE hList;
1838 rc = HGCMSvcGetU64(&aParms[1], &hList); /* Get list handle. */
1839 if (RT_SUCCESS(rc))
1840 {
1841 SHCLLISTENTRY entryList;
1842 rc = ShClTransferListEntryInit(&entryList);
1843 if (RT_SUCCESS(rc))
1844 {
1845 rc = ShClTransferListRead(pTransfer, hList, &entryList);
1846 if (RT_SUCCESS(rc))
1847 rc = shClSvcTransferMsgSetListEntry(cParms, aParms, &entryList);
1848 }
1849 }
1850 break;
1851 }
1852
1853 case VBOX_SHCL_GUEST_FN_LIST_ENTRY_WRITE:
1854 {
1855 SHCLLISTENTRY entryList;
1856 rc = ShClTransferListEntryInit(&entryList);
1857 if (RT_SUCCESS(rc))
1858 {
1859 SHCLLISTHANDLE hList;
1860 rc = shClSvcTransferMsgGetListEntry(cParms, aParms, &hList, &entryList);
1861 if (RT_SUCCESS(rc))
1862 {
1863 void *pvData = ShClTransferListEntryDup(&entryList);
1864 uint32_t cbData = sizeof(SHCLLISTENTRY);
1865
1866 const PSHCLEVENT pEvent = ShClEventSourceGetFromId(&pTransfer->Events, VBOX_SHCL_CONTEXTID_GET_EVENT(uCID));
1867 if (pEvent)
1868 {
1869 PSHCLEVENTPAYLOAD pPayload;
1870 rc = ShClPayloadAlloc(pEvent->idEvent, pvData, cbData, &pPayload);
1871 if (RT_SUCCESS(rc))
1872 {
1873 rc = ShClEventSignal(pEvent, pPayload);
1874 if (RT_FAILURE(rc))
1875 ShClPayloadFree(pPayload);
1876 }
1877 }
1878 else
1879 rc = VERR_SHCLPB_EVENT_ID_NOT_FOUND;
1880 }
1881 }
1882 break;
1883 }
1884
1885 case VBOX_SHCL_GUEST_FN_OBJ_OPEN:
1886 {
1887 ASSERT_GUEST_STMT_BREAK(cParms == VBOX_SHCL_CPARMS_OBJ_OPEN, rc = VERR_WRONG_PARAMETER_COUNT);
1888
1889 SHCLOBJOPENCREATEPARMS openCreateParms;
1890 RT_ZERO(openCreateParms);
1891
1892 /* aParms[1] will return the object handle on success; see below. */
1893 rc = HGCMSvcGetStr(&aParms[2], &openCreateParms.pszPath, &openCreateParms.cbPath);
1894 if (RT_SUCCESS(rc))
1895 rc = HGCMSvcGetU32(&aParms[3], &openCreateParms.fCreate);
1896
1897 if (RT_SUCCESS(rc))
1898 {
1899 SHCLOBJHANDLE hObj;
1900 rc = ShClTransferObjOpen(pTransfer, &openCreateParms, &hObj);
1901 if (RT_SUCCESS(rc))
1902 {
1903 LogFlowFunc(("hObj=%RU64\n", hObj));
1904
1905 HGCMSvcSetU64(&aParms[1], hObj);
1906 }
1907 }
1908 break;
1909 }
1910
1911 case VBOX_SHCL_GUEST_FN_OBJ_CLOSE:
1912 {
1913 if (cParms != VBOX_SHCL_CPARMS_OBJ_CLOSE)
1914 break;
1915
1916 SHCLOBJHANDLE hObj;
1917 rc = HGCMSvcGetU64(&aParms[1], &hObj); /* Get object handle. */
1918 if (RT_SUCCESS(rc))
1919 rc = ShClTransferObjClose(pTransfer, hObj);
1920 break;
1921 }
1922
1923 case VBOX_SHCL_GUEST_FN_OBJ_READ:
1924 {
1925 if (cParms != VBOX_SHCL_CPARMS_OBJ_READ)
1926 break;
1927
1928 ASSERT_GUEST_RETURN(aParms[1].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE); /* Object handle */
1929 ASSERT_GUEST_RETURN(aParms[2].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE); /* Bytes to read */
1930 ASSERT_GUEST_RETURN(aParms[3].type == VBOX_HGCM_SVC_PARM_PTR, VERR_WRONG_PARAMETER_TYPE); /* Data buffer */
1931 ASSERT_GUEST_RETURN(aParms[4].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE); /* Checksum data size */
1932 ASSERT_GUEST_RETURN(aParms[5].type == VBOX_HGCM_SVC_PARM_PTR, VERR_WRONG_PARAMETER_TYPE); /* Checksum data buffer*/
1933
1934 SHCLOBJHANDLE hObj;
1935 rc = HGCMSvcGetU64(&aParms[1], &hObj); /* Get object handle. */
1936 AssertRCBreak(rc);
1937
1938 uint32_t cbToRead = 0;
1939 rc = HGCMSvcGetU32(&aParms[2], &cbToRead);
1940 AssertRCBreak(rc);
1941
1942 void *pvBuf = NULL;
1943 uint32_t cbBuf = 0;
1944 rc = HGCMSvcGetPv(&aParms[3], &pvBuf, &cbBuf);
1945 AssertRCBreak(rc);
1946
1947 LogFlowFunc(("hObj=%RU64, cbBuf=%RU32, cbToRead=%RU32, rc=%Rrc\n", hObj, cbBuf, cbToRead, rc));
1948
1949 if ( RT_SUCCESS(rc)
1950 && ( !cbBuf
1951 || !cbToRead
1952 || cbBuf < cbToRead
1953 )
1954 )
1955 {
1956 rc = VERR_INVALID_PARAMETER;
1957 }
1958
1959 if (RT_SUCCESS(rc))
1960 {
1961 uint32_t cbRead;
1962 rc = ShClTransferObjRead(pTransfer, hObj, pvBuf, cbToRead, 0 /* fFlags */, &cbRead);
1963 if (RT_SUCCESS(rc))
1964 {
1965 HGCMSvcSetU32(&aParms[2], cbRead);
1966
1967 /** @todo Implement checksum support. */
1968 }
1969 }
1970 break;
1971 }
1972
1973 case VBOX_SHCL_GUEST_FN_OBJ_WRITE:
1974 {
1975 SHCLOBJDATACHUNK dataChunk;
1976
1977 rc = shClSvcTransferGetObjDataChunk(cParms, aParms, &dataChunk);
1978 if (RT_SUCCESS(rc))
1979 {
1980 void *pvData = ShClTransferObjDataChunkDup(&dataChunk);
1981 uint32_t cbData = sizeof(SHCLOBJDATACHUNK);
1982
1983 const PSHCLEVENT pEvent = ShClEventSourceGetFromId(&pTransfer->Events, VBOX_SHCL_CONTEXTID_GET_EVENT(uCID));
1984 if (pEvent)
1985 {
1986 PSHCLEVENTPAYLOAD pPayload;
1987 rc = ShClPayloadAlloc(pEvent->idEvent, pvData, cbData, &pPayload);
1988 if (RT_SUCCESS(rc))
1989 {
1990 rc = ShClEventSignal(pEvent, pPayload);
1991 if (RT_FAILURE(rc))
1992 ShClPayloadFree(pPayload);
1993 }
1994 }
1995 else
1996 rc = VERR_SHCLPB_EVENT_ID_NOT_FOUND;
1997 }
1998
1999 break;
2000 }
2001
2002 default:
2003 rc = VERR_NOT_IMPLEMENTED;
2004 break;
2005 }
2006
2007 /* If anything wrong has happened, make sure to unregister the transfer again (if not done already) and tell the guest. */
2008 if ( RT_FAILURE(rc)
2009 && pTransfer)
2010 {
2011 ShClSvcClientLock(pClient);
2012
2013 /* Let the guest know. */
2014 int rc2 = shClSvcTransferSendStatusAsync(pClient, pTransfer,
2015 SHCLTRANSFERSTATUS_ERROR, rc, NULL /* ppEvent */);
2016 AssertRC(rc2);
2017
2018 ShClSvcClientUnlock(pClient);
2019
2020 ShClSvcTransferDestroy(pClient, pTransfer);
2021 }
2022
2023 LogFlowFunc(("[Client %RU32] Returning rc=%Rrc\n", pClient->State.uClientID, rc));
2024 return rc;
2025}
2026
2027/**
2028 * Transfer message host handler for the Shared Clipboard host service.
2029 *
2030 * @returns VBox status code.
2031 * @param u32Function Function number being called.
2032 * @param cParms Number of function parameters supplied.
2033 * @param aParms Array function parameters supplied.
2034 */
2035int ShClSvcTransferMsgHostHandler(uint32_t u32Function,
2036 uint32_t cParms,
2037 VBOXHGCMSVCPARM aParms[])
2038{
2039 RT_NOREF(cParms, aParms);
2040
2041 int rc = VERR_NOT_IMPLEMENTED; /* Play safe. */
2042
2043 switch (u32Function)
2044 {
2045 case VBOX_SHCL_HOST_FN_CANCEL: /** @todo BUGBUG Implement this. */
2046 break;
2047
2048 case VBOX_SHCL_HOST_FN_ERROR: /** @todo BUGBUG Implement this. */
2049 break;
2050
2051 default:
2052 break;
2053
2054 }
2055
2056 LogFlowFuncLeaveRC(rc);
2057 return rc;
2058}
2059
2060int shClSvcTransferHostMsgHandler(PSHCLCLIENT pClient, PSHCLCLIENTMSG pMsg)
2061{
2062 RT_NOREF(pClient);
2063
2064 int rc;
2065
2066 switch (pMsg->idMsg)
2067 {
2068 default:
2069 rc = VINF_SUCCESS;
2070 break;
2071 }
2072
2073 LogFlowFuncLeaveRC(rc);
2074 return rc;
2075}
2076
2077/**
2078 * Reports a transfer status to the guest.
2079 *
2080 * @returns VBox status code.
2081 * @param pClient Client that owns the transfer.
2082 * @param idTransfer Transfer ID to report status for.
2083 * @param enmDir Transfer direction to report status for.
2084 * @param enmSts Status to report.
2085 * @param rcTransfer Result code to report. Optional and depending on status.
2086 * @param ppEvent Where to return the wait event on success. Optional.
2087 * Must be released by the caller with ShClEventRelease().
2088 *
2089 * @note Caller must enter the client's critical section.
2090 */
2091static int shClSvcTransferSendStatusExAsync(PSHCLCLIENT pClient, SHCLTRANSFERID idTransfer,
2092 SHCLTRANSFERDIR enmDir, SHCLTRANSFERSTATUS enmSts, int rcTransfer,
2093 PSHCLEVENT *ppEvent)
2094{
2095 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
2096 AssertReturn(idTransfer != NIL_SHCLTRANSFERID, VERR_INVALID_PARAMETER);
2097 /* ppEvent is optional. */
2098
2099 Assert(RTCritSectIsOwner(&pClient->CritSect));
2100
2101 PSHCLCLIENTMSG pMsgReadData = ShClSvcClientMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_STATUS,
2102 VBOX_SHCL_CPARMS_TRANSFER_STATUS);
2103 if (!pMsgReadData)
2104 return VERR_NO_MEMORY;
2105
2106 PSHCLEVENT pEvent;
2107 int rc = ShClEventSourceGenerateAndRegisterEvent(&pClient->EventSrc, &pEvent);
2108 if (RT_SUCCESS(rc))
2109 {
2110 HGCMSvcSetU64(&pMsgReadData->aParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID, idTransfer, pEvent->idEvent));
2111 HGCMSvcSetU32(&pMsgReadData->aParms[1], enmDir);
2112 HGCMSvcSetU32(&pMsgReadData->aParms[2], enmSts);
2113 HGCMSvcSetU32(&pMsgReadData->aParms[3], (uint32_t)rcTransfer); /** @todo uint32_t vs. int. */
2114 HGCMSvcSetU32(&pMsgReadData->aParms[4], 0 /* fFlags, unused */);
2115
2116 ShClSvcClientMsgAdd(pClient, pMsgReadData, true /* fAppend */);
2117
2118 rc = ShClSvcClientWakeup(pClient);
2119 if (RT_SUCCESS(rc))
2120 {
2121 LogRel2(("Shared Clipboard: Reported status %s (rc=%Rrc) of transfer %RU16 to guest\n",
2122 ShClTransferStatusToStr(enmSts), rcTransfer, idTransfer));
2123
2124 if (ppEvent)
2125 {
2126 *ppEvent = pEvent; /* Takes ownership. */
2127 }
2128 else /* If event is not consumed by the caller, release the event again. */
2129 ShClEventRelease(pEvent);
2130 }
2131 else
2132 ShClEventRelease(pEvent);
2133 }
2134 else
2135 rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
2136
2137 if (RT_FAILURE(rc))
2138 LogRelMax(64, ("Shared Clipboard: Reporting status %s (%Rrc) for transfer %RU16 to guest failed with %Rrc\n",
2139 ShClTransferStatusToStr(enmSts), rcTransfer, idTransfer, rc));
2140
2141 LogFlowFuncLeaveRC(rc);
2142 return rc;
2143}
2144
2145/**
2146 * Reports a transfer status to the guest, internal version.
2147 *
2148 * @returns VBox status code.
2149 * @param pClient Client that owns the transfer.
2150 * @param pTransfer Transfer to report status for.
2151 * @param enmSts Status to report.
2152 * @param rcTransfer Result code to report. Optional and depending on status.
2153 * @param ppEvent Where to return the wait event on success. Optional.
2154 * Must be released by the caller with ShClEventRelease().
2155 *
2156 * @note Caller must enter the client's critical section.
2157 */
2158static int shClSvcTransferSendStatusAsync(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, SHCLTRANSFERSTATUS enmSts,
2159 int rcTransfer, PSHCLEVENT *ppEvent)
2160{
2161 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
2162 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2163 /* ppEvent is optional. */
2164
2165 return shClSvcTransferSendStatusExAsync(pClient, ShClTransferGetID(pTransfer), ShClTransferGetDir(pTransfer),
2166 enmSts, rcTransfer, ppEvent);
2167}
2168
2169/**
2170 * Reports a transfer status to the guest.
2171 *
2172 * @returns VBox status code.
2173 * @param pClient Client that owns the transfer.
2174 * @param pTransfer Transfer to report status for.
2175 * @param enmSts Status to report.
2176 * @param rcTransfer Result code to report. Optional and depending on status.
2177 * @param ppEvent Where to return the wait event on success. Optional.
2178 * Must be released by the caller with ShClEventRelease().
2179 */
2180int ShClSvcTransferSendStatusAsync(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, SHCLTRANSFERSTATUS enmSts,
2181 int rcTransfer, PSHCLEVENT *ppEvent)
2182{
2183 return shClSvcTransferSendStatusAsync(pClient, pTransfer, enmSts, rcTransfer, ppEvent);
2184}
2185
2186/**
2187 * Cleans up (unregisters and destroys) all transfers not in started state (anymore).
2188 *
2189 * @param pClient Client to clean up transfers for.
2190 *
2191 * @note Caller needs to take the critical section.
2192 */
2193static void shClSvcTransferCleanupAllUnused(PSHCLCLIENT pClient)
2194{
2195 Assert(RTCritSectIsOwner(&pClient->CritSect));
2196
2197 LogFlowFuncEnter();
2198
2199 PSHCLTRANSFERCTX pTxCtx = &pClient->Transfers.Ctx;
2200
2201 PSHCLTRANSFER pTransfer, pTransferNext;
2202 RTListForEachSafe(&pTxCtx->List, pTransfer, pTransferNext, SHCLTRANSFER, Node)
2203 {
2204 SHCLTRANSFERSTATUS const enmSts = ShClTransferGetStatus(pTransfer);
2205 if (enmSts != SHCLTRANSFERSTATUS_STARTED)
2206 {
2207 /* Let the guest know. */
2208 int rc2 = shClSvcTransferSendStatusAsync(pClient, pTransfer,
2209 SHCLTRANSFERSTATUS_UNINITIALIZED, VINF_SUCCESS, NULL /* ppEvent */);
2210 AssertRC(rc2);
2211
2212 ShClTransferCtxUnregisterById(pTxCtx, pTransfer->State.uID);
2213 ShClTransferDestroy(pTransfer);
2214 }
2215 }
2216}
2217
2218/**
2219 * Creates a new transfer on the host.
2220 *
2221 * @returns VBox status code.
2222 * @param pClient Client that owns the transfer.
2223 * @param enmDir Transfer direction to create.
2224 * @param enmSource Transfer source to create.
2225 * @param idTransfer Transfer ID to use for creation.
2226 * If set to NIL_SHCLTRANSFERID, a new transfer ID will be created.
2227 * @param ppTransfer Where to return the created transfer on success. Optional and can be NULL.
2228 */
2229int ShClSvcTransferCreate(PSHCLCLIENT pClient, SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource, SHCLTRANSFERID idTransfer, PSHCLTRANSFER *ppTransfer)
2230{
2231 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
2232 /* ppTransfer is optional. */
2233
2234 LogFlowFuncEnter();
2235
2236 ShClSvcClientLock(pClient);
2237
2238 /* When creating a new transfer, this is a good time to clean up old stuff we don't need anymore. */
2239 shClSvcTransferCleanupAllUnused(pClient);
2240
2241 PSHCLTRANSFER pTransfer;
2242 int rc = ShClTransferCreate(enmDir, enmSource, &pClient->Transfers.Callbacks, &pTransfer);
2243 if (RT_SUCCESS(rc))
2244 {
2245 if (idTransfer == NIL_SHCLTRANSFERID)
2246 rc = ShClTransferCtxRegister(&pClient->Transfers.Ctx, pTransfer, &idTransfer);
2247 else
2248 rc = ShClTransferCtxRegisterById(&pClient->Transfers.Ctx, pTransfer, idTransfer);
2249 if (RT_SUCCESS(rc))
2250 {
2251 if (ppTransfer)
2252 *ppTransfer = pTransfer;
2253 }
2254 }
2255
2256 ShClSvcClientUnlock(pClient);
2257
2258 if (RT_FAILURE(rc))
2259 ShClTransferDestroy(pTransfer);
2260
2261 if (RT_FAILURE(rc))
2262 LogRel(("Shared Clipboard: Creating transfer failed with %Rrc\n", rc));
2263
2264 LogFlowFuncLeaveRC(rc);
2265 return rc;
2266}
2267
2268/**
2269 * Destroys a transfer on the host.
2270 *
2271 * @param pClient Client to destroy transfer for.
2272 * @param pTransfer Transfer to destroy.
2273 * The pointer will be invalid after return.
2274 */
2275void ShClSvcTransferDestroy(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
2276{
2277 if (!pTransfer)
2278 return;
2279
2280 LogFlowFuncEnter();
2281
2282 ShClSvcClientLock(pClient);
2283
2284 PSHCLTRANSFERCTX pTxCtx = &pClient->Transfers.Ctx;
2285
2286 ShClTransferCtxUnregisterById(pTxCtx, pTransfer->State.uID);
2287
2288 /* Make sure to let the guest know. */
2289 int rc = shClSvcTransferSendStatusAsync(pClient, pTransfer,
2290 SHCLTRANSFERSTATUS_UNINITIALIZED, VINF_SUCCESS, NULL /* ppEvent */);
2291 AssertRC(rc);
2292
2293 ShClTransferDestroy(pTransfer);
2294 pTransfer = NULL;
2295
2296 ShClSvcClientUnlock(pClient);
2297
2298 LogFlowFuncLeave();
2299}
2300
2301/**
2302 * Initializes a (created) transfer on the host.
2303 *
2304 * @returns VBox status code.
2305 * @param pClient Client that owns the transfer.
2306 * @param pTransfer Transfer to initialize.
2307 */
2308int ShClSvcTransferInit(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
2309{
2310 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
2311
2312 LogFlowFuncEnter();
2313
2314 ShClSvcClientLock(pClient);
2315
2316 Assert(ShClTransferGetStatus(pTransfer) == SHCLTRANSFERSTATUS_NONE);
2317
2318 PSHCLTRANSFERCTX pTxCtx = &pClient->Transfers.Ctx;
2319
2320 int rc;
2321
2322 if (!ShClTransferCtxIsMaximumReached(pTxCtx))
2323 {
2324 SHCLTRANSFERDIR const enmDir = ShClTransferGetDir(pTransfer);
2325
2326 LogRel2(("Shared Clipboard: Initializing %s transfer ...\n",
2327 enmDir == SHCLTRANSFERDIR_FROM_REMOTE ? "guest -> host" : "host -> guest"));
2328
2329 rc = ShClTransferInit(pTransfer);
2330 }
2331 else
2332 rc = VERR_SHCLPB_MAX_TRANSFERS_REACHED;
2333
2334 /* Tell the guest the outcome. */
2335 int rc2 = shClSvcTransferSendStatusAsync(pClient, pTransfer,
2336 RT_SUCCESS(rc)
2337 ? SHCLTRANSFERSTATUS_INITIALIZED : SHCLTRANSFERSTATUS_ERROR, rc,
2338 NULL /* ppEvent */);
2339 if (RT_SUCCESS(rc))
2340 rc2 = rc;
2341
2342 if (RT_FAILURE(rc))
2343 LogRel(("Shared Clipboard: Initializing transfer failed with %Rrc\n", rc));
2344
2345 ShClSvcClientUnlock(pClient);
2346
2347 LogFlowFuncLeaveRC(rc);
2348 return rc;
2349}
2350
2351/**
2352 * Starts a transfer, communicating the status to the guest side.
2353 *
2354 * @returns VBox status code.
2355 * @param pClient Client that owns the transfer.
2356 * @param pTransfer Transfer to start.
2357 */
2358int ShClSvcTransferStart(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
2359{
2360 LogRel2(("Shared Clipboard: Starting transfer %RU16 ...\n", pTransfer->State.uID));
2361
2362 ShClSvcClientLock(pClient);
2363
2364 int rc = ShClTransferStart(pTransfer);
2365
2366 /* Let the guest know in any case
2367 * (so that it can tear down the transfer on error as well). */
2368 int rc2 = shClSvcTransferSendStatusAsync(pClient, pTransfer,
2369 RT_SUCCESS(rc)
2370 ? SHCLTRANSFERSTATUS_STARTED : SHCLTRANSFERSTATUS_ERROR, rc,
2371 NULL /* ppEvent */);
2372 if (RT_SUCCESS(rc))
2373 rc = rc2;
2374
2375 ShClSvcClientUnlock(pClient);
2376 return rc;
2377}
2378
2379/**
2380 * Stops (and destroys) a transfer, communicating the status to the guest side.
2381 *
2382 * @returns VBox status code.
2383 * @param pClient Client that owns the transfer.
2384 * @param pTransfer Transfer to stop. The pointer will be invalid on success.
2385 * @param fWaitForGuest Set to \c true to wait for acknowledgement from guest, or \c false to skip waiting.
2386 */
2387int ShClSvcTransferStop(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, bool fWaitForGuest)
2388{
2389 LogRel2(("Shared Clipboard: Stopping transfer %RU16 ...\n", pTransfer->State.uID));
2390
2391 ShClSvcClientLock(pClient);
2392
2393 PSHCLEVENT pEvent;
2394 int rc = shClSvcTransferSendStatusAsync(pClient, pTransfer,
2395 SHCLTRANSFERSTATUS_COMPLETED, VINF_SUCCESS, &pEvent);
2396 if ( RT_SUCCESS(rc)
2397 && fWaitForGuest)
2398 {
2399 LogRel2(("Shared Clipboard: Waiting for stop of transfer %RU16 on guest ...\n", pTransfer->State.uID));
2400
2401 ShClSvcClientUnlock(pClient);
2402
2403 rc = ShClEventWait(pEvent, pTransfer->uTimeoutMs, NULL /* ppPayload */);
2404 if (RT_SUCCESS(rc))
2405 LogRel2(("Shared Clipboard: Stopped transfer %RU16 on guest\n", pTransfer->State.uID));
2406
2407 ShClEventRelease(pEvent);
2408
2409 ShClSvcClientLock(pClient);
2410 }
2411
2412 if (RT_FAILURE(rc))
2413 LogRelMax(64, ("Shared Clipboard: Unable to stop transfer %RU16 on guest, rc=%Rrc\n",
2414 pTransfer->State.uID, rc));
2415
2416 ShClSvcClientUnlock(pClient);
2417
2418 LogFlowFuncLeaveRC(rc);
2419 return rc;
2420}
2421
2422/**
2423 * Sets the host service's (file) transfer mode.
2424 *
2425 * @returns VBox status code.
2426 * @param fMode Transfer mode to set.
2427 */
2428int shClSvcTransferModeSet(uint32_t fMode)
2429{
2430 if (fMode & ~VBOX_SHCL_TRANSFER_MODE_F_VALID_MASK)
2431 return VERR_INVALID_FLAGS;
2432
2433 g_fTransferMode = fMode;
2434
2435 LogRel2(("Shared Clipboard: File transfers are now %s\n",
2436 g_fTransferMode & VBOX_SHCL_TRANSFER_MODE_F_ENABLED ? "enabled" : "disabled"));
2437
2438 /* If file transfers are being disabled, make sure to also reset (destroy) all pending transfers. */
2439 if (!(g_fTransferMode & VBOX_SHCL_TRANSFER_MODE_F_ENABLED))
2440 {
2441 ClipboardClientMap::const_iterator itClient = g_mapClients.begin();
2442 while (itClient != g_mapClients.end())
2443 {
2444 PSHCLCLIENT pClient = itClient->second;
2445 AssertPtr(pClient);
2446
2447 shClSvcTransferDestroyAll(pClient);
2448
2449 ++itClient;
2450 }
2451 }
2452
2453 LogFlowFuncLeaveRC(VINF_SUCCESS);
2454 return VINF_SUCCESS;
2455}
Note: See TracBrowser for help on using the repository browser.

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