VirtualBox

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

Last change on this file since 100562 was 100562, checked in by vboxsync, 19 months ago

Shared Clipboard: Use the transfer's event source in the host service when creating events instead of the client's event source -- this allows more fine-grained resetting (later). bugref:9437

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