VirtualBox

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

Last change on this file since 94348 was 93495, checked in by vboxsync, 3 years ago

Shared Clipboard: Implemented backend callbacks and a dedicated backend context, together with a new testcase which mocks HGCM to also test the guest-side clipboard code (disabled by default for now). Work in progress, only tested on Linux so far.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 71.6 KB
Line 
1/* $Id: VBoxSharedClipboardSvc-transfers.cpp 93495 2022-01-31 13:08:33Z vboxsync $ */
2/** @file
3 * Shared Clipboard Service - Internal code for transfer (list) handling.
4 */
5
6/*
7 * Copyright (C) 2019-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
23#include <VBox/log.h>
24
25#include <VBox/err.h>
26
27#include <VBox/GuestHost/clipboard-helper.h>
28#include <VBox/HostServices/VBoxClipboardSvc.h>
29#include <VBox/HostServices/VBoxClipboardExt.h>
30
31#include <VBox/AssertGuest.h>
32#include <iprt/dir.h>
33#include <iprt/file.h>
34#include <iprt/path.h>
35
36#include "VBoxSharedClipboardSvc-internal.h"
37#include "VBoxSharedClipboardSvc-transfers.h"
38
39
40/*********************************************************************************************************************************
41* Externals *
42*********************************************************************************************************************************/
43extern uint32_t g_fTransferMode;
44extern SHCLEXTSTATE g_ExtState;
45extern PVBOXHGCMSVCHELPERS g_pHelpers;
46extern ClipboardClientMap g_mapClients;
47extern ClipboardClientQueue g_listClientsDeferred;
48
49
50/*********************************************************************************************************************************
51* Prototypes *
52*********************************************************************************************************************************/
53static int shClSvcTransferSetListOpen(uint32_t cParms, VBOXHGCMSVCPARM aParms[],
54 uint64_t idCtx, PSHCLLISTOPENPARMS pOpenParms);
55static int shClSvcTransferSetListClose(uint32_t cParms, VBOXHGCMSVCPARM aParms[],
56 uint64_t idCtx, SHCLLISTHANDLE hList);
57
58
59/*********************************************************************************************************************************
60* Provider implementation *
61*********************************************************************************************************************************/
62
63/**
64 * Resets all transfers of a Shared Clipboard client.
65 *
66 * @param pClient Client to reset transfers for.
67 */
68void shClSvcClientTransfersReset(PSHCLCLIENT pClient)
69{
70 if (!pClient)
71 return;
72
73 LogFlowFuncEnter();
74
75 /* Make sure to let the backend know that all transfers are getting destroyed. */
76 uint32_t uIdx = 0;
77 PSHCLTRANSFER pTransfer;
78 while ((pTransfer = ShClTransferCtxGetTransferByIndex(&pClient->Transfers.Ctx, uIdx++)))
79 ShClBackendTransferDestroy(pClient->pBackend, pClient, pTransfer);
80
81 ShClTransferCtxDestroy(&pClient->Transfers.Ctx);
82}
83
84
85/*********************************************************************************************************************************
86* Provider interface implementation *
87*********************************************************************************************************************************/
88
89DECLCALLBACK(int) shClSvcTransferIfaceGetRoots(PSHCLTXPROVIDERCTX pCtx, PSHCLROOTLIST *ppRootList)
90{
91 LogFlowFuncEnter();
92
93 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
94 AssertPtr(pClient);
95
96 int rc;
97
98 PSHCLCLIENTMSG pMsgHdr = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ,
99 VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ_REQ);
100 if (pMsgHdr)
101 {
102 PSHCLEVENT pEvent;
103 rc = ShClEventSourceGenerateAndRegisterEvent(&pClient->EventSrc, &pEvent);
104 if (RT_SUCCESS(rc))
105 {
106 HGCMSvcSetU64(&pMsgHdr->aParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
107 pCtx->pTransfer->State.uID, pEvent->idEvent));
108 HGCMSvcSetU32(&pMsgHdr->aParms[1], 0 /* fRoots */);
109
110 shClSvcClientLock(pClient);
111
112 shClSvcMsgAdd(pClient, pMsgHdr, true /* fAppend */);
113 rc = shClSvcClientWakeup(pClient);
114
115 shClSvcClientUnlock(pClient);
116
117 if (RT_SUCCESS(rc))
118 {
119 PSHCLEVENTPAYLOAD pPayloadHdr;
120 rc = ShClEventWait(pEvent, pCtx->pTransfer->uTimeoutMs, &pPayloadHdr);
121 if (RT_SUCCESS(rc))
122 {
123 PSHCLROOTLISTHDR pSrcRootListHdr = (PSHCLROOTLISTHDR)pPayloadHdr->pvData;
124 Assert(pPayloadHdr->cbData == sizeof(SHCLROOTLISTHDR));
125
126 LogFlowFunc(("cRoots=%RU32, fRoots=0x%x\n", pSrcRootListHdr->cRoots, pSrcRootListHdr->fRoots));
127
128 PSHCLROOTLIST pRootList = ShClTransferRootListAlloc();
129 if (pRootList)
130 {
131 if (pSrcRootListHdr->cRoots)
132 {
133 pRootList->paEntries =
134 (PSHCLROOTLISTENTRY)RTMemAllocZ(pSrcRootListHdr->cRoots * sizeof(SHCLROOTLISTENTRY));
135
136 if (pRootList->paEntries)
137 {
138 for (uint32_t i = 0; i < pSrcRootListHdr->cRoots; i++)
139 {
140 PSHCLCLIENTMSG pMsgEntry = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ,
141 VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ_REQ);
142
143 PSHCLEVENT pEvRoot;
144 rc = ShClEventSourceGenerateAndRegisterEvent(&pClient->EventSrc, &pEvRoot);
145 if (RT_SUCCESS(rc))
146 {
147 HGCMSvcSetU64(&pMsgEntry->aParms[0],
148 VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uClientID,
149 pCtx->pTransfer->State.uID, pEvRoot->idEvent));
150 HGCMSvcSetU32(&pMsgEntry->aParms[1], 0 /* fRoots */);
151 HGCMSvcSetU32(&pMsgEntry->aParms[2], i /* uIndex */);
152
153 shClSvcClientLock(pClient);
154 shClSvcMsgAdd(pClient, pMsgEntry, true /* fAppend */);
155 shClSvcClientUnlock(pClient);
156
157 PSHCLEVENTPAYLOAD pPayloadEntry;
158 rc = ShClEventWait(pEvent, pCtx->pTransfer->uTimeoutMs, &pPayloadEntry);
159 if (RT_FAILURE(rc))
160 break;
161
162 PSHCLROOTLISTENTRY pSrcRootListEntry = (PSHCLROOTLISTENTRY)pPayloadEntry->pvData;
163 Assert(pPayloadEntry->cbData == sizeof(SHCLROOTLISTENTRY));
164
165 rc = ShClTransferListEntryCopy(&pRootList->paEntries[i], pSrcRootListEntry);
166
167 ShClPayloadFree(pPayloadEntry);
168
169 ShClEventRelease(pEvRoot);
170 pEvRoot = NULL;
171 }
172 else
173 rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
174
175 if (RT_FAILURE(rc))
176 break;
177 }
178 }
179 else
180 rc = VERR_NO_MEMORY;
181 }
182
183 if (RT_SUCCESS(rc))
184 {
185 pRootList->Hdr.cRoots = pSrcRootListHdr->cRoots;
186 pRootList->Hdr.fRoots = 0; /** @todo Implement this. */
187
188 *ppRootList = pRootList;
189 }
190 else
191 ShClTransferRootListFree(pRootList);
192
193 ShClPayloadFree(pPayloadHdr);
194 }
195 else
196 rc = VERR_NO_MEMORY;
197 }
198 }
199
200 ShClEventRelease(pEvent);
201 }
202 else
203 rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
204 }
205 else
206 rc = VERR_NO_MEMORY;
207
208 LogFlowFuncLeave();
209 return rc;
210}
211
212DECLCALLBACK(int) shClSvcTransferIfaceListOpen(PSHCLTXPROVIDERCTX pCtx,
213 PSHCLLISTOPENPARMS pOpenParms, PSHCLLISTHANDLE phList)
214{
215 LogFlowFuncEnter();
216
217 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
218 AssertPtr(pClient);
219
220 int rc;
221
222 PSHCLCLIENTMSG pMsg = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN,
223 VBOX_SHCL_CPARMS_LIST_OPEN);
224 if (pMsg)
225 {
226 PSHCLEVENT pEvent;
227 rc = ShClEventSourceGenerateAndRegisterEvent(&pClient->EventSrc, &pEvent);
228 if (RT_SUCCESS(rc))
229 {
230 pMsg->idCtx = VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID, pCtx->pTransfer->State.uID,
231 pEvent->idEvent);
232
233 rc = shClSvcTransferSetListOpen(pMsg->cParms, pMsg->aParms, pMsg->idCtx, pOpenParms);
234 if (RT_SUCCESS(rc))
235 {
236 shClSvcMsgAdd(pClient, pMsg, true /* fAppend */);
237
238 rc = shClSvcClientWakeup(pClient);
239 if (RT_SUCCESS(rc))
240 {
241 PSHCLEVENTPAYLOAD pPayload;
242 rc = ShClEventWait(pEvent, pCtx->pTransfer->uTimeoutMs, &pPayload);
243 if (RT_SUCCESS(rc))
244 {
245 Assert(pPayload->cbData == sizeof(SHCLREPLY));
246
247 PSHCLREPLY pReply = (PSHCLREPLY)pPayload->pvData;
248 AssertPtr(pReply);
249
250 Assert(pReply->uType == VBOX_SHCL_REPLYMSGTYPE_LIST_OPEN);
251
252 LogFlowFunc(("hList=%RU64\n", pReply->u.ListOpen.uHandle));
253
254 *phList = pReply->u.ListOpen.uHandle;
255
256 ShClPayloadFree(pPayload);
257 }
258 }
259 }
260
261 ShClEventRelease(pEvent);
262 }
263 else
264 rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
265 }
266 else
267 rc = VERR_NO_MEMORY;
268
269 LogFlowFuncLeaveRC(rc);
270 return rc;
271}
272
273DECLCALLBACK(int) shClSvcTransferIfaceListClose(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList)
274{
275 LogFlowFuncEnter();
276
277 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
278 AssertPtr(pClient);
279
280 int rc;
281
282 PSHCLCLIENTMSG pMsg = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE,
283 VBOX_SHCL_CPARMS_LIST_CLOSE);
284 if (pMsg)
285 {
286 PSHCLEVENT pEvent;
287 rc = ShClEventSourceGenerateAndRegisterEvent(&pClient->EventSrc, &pEvent);
288 if (RT_SUCCESS(rc))
289 {
290 pMsg->idCtx = VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID, pCtx->pTransfer->State.uID,
291 pEvent->idEvent);
292
293 rc = shClSvcTransferSetListClose(pMsg->cParms, pMsg->aParms, pMsg->idCtx, hList);
294 if (RT_SUCCESS(rc))
295 {
296 shClSvcMsgAdd(pClient, pMsg, true /* fAppend */);
297
298 rc = shClSvcClientWakeup(pClient);
299 if (RT_SUCCESS(rc))
300 {
301 PSHCLEVENTPAYLOAD pPayload;
302 rc = ShClEventWait(pEvent, pCtx->pTransfer->uTimeoutMs, &pPayload);
303 if (RT_SUCCESS(rc))
304 ShClPayloadFree(pPayload);
305 }
306 }
307
308 ShClEventRelease(pEvent);
309 }
310 else
311 rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
312 }
313 else
314 rc = VERR_NO_MEMORY;
315
316 LogFlowFuncLeaveRC(rc);
317 return rc;
318}
319
320DECLCALLBACK(int) shClSvcTransferIfaceListHdrRead(PSHCLTXPROVIDERCTX pCtx,
321 SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)
322{
323 LogFlowFuncEnter();
324
325 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
326 AssertPtr(pClient);
327
328 int rc;
329
330 PSHCLCLIENTMSG pMsg = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ,
331 VBOX_SHCL_CPARMS_LIST_HDR_READ_REQ);
332 if (pMsg)
333 {
334 PSHCLEVENT pEvent;
335 rc = ShClEventSourceGenerateAndRegisterEvent(&pClient->EventSrc, &pEvent);
336 if (RT_SUCCESS(rc))
337 {
338 HGCMSvcSetU64(&pMsg->aParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
339 pCtx->pTransfer->State.uID, pEvent->idEvent));
340 HGCMSvcSetU64(&pMsg->aParms[1], hList);
341 HGCMSvcSetU32(&pMsg->aParms[2], 0 /* fFlags */);
342
343 shClSvcMsgAdd(pClient, pMsg, true /* fAppend */);
344
345 rc = shClSvcClientWakeup(pClient);
346 if (RT_SUCCESS(rc))
347 {
348 PSHCLEVENTPAYLOAD pPayload;
349 rc = ShClEventWait(pEvent, pCtx->pTransfer->uTimeoutMs, &pPayload);
350 if (RT_SUCCESS(rc))
351 {
352 Assert(pPayload->cbData == sizeof(SHCLLISTHDR));
353
354 *pListHdr = *(PSHCLLISTHDR)pPayload->pvData;
355
356 ShClPayloadFree(pPayload);
357 }
358 }
359
360 ShClEventRelease(pEvent);
361 }
362 else
363 rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
364 }
365 else
366 rc = VERR_NO_MEMORY;
367
368 LogFlowFuncLeaveRC(rc);
369 return rc;
370}
371
372DECLCALLBACK(int) shClSvcTransferIfaceListHdrWrite(PSHCLTXPROVIDERCTX pCtx,
373 SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)
374{
375 RT_NOREF(pCtx, hList, pListHdr);
376
377 LogFlowFuncEnter();
378
379 return VERR_NOT_IMPLEMENTED;
380}
381
382DECLCALLBACK(int) shClSvcTransferIfaceListEntryRead(PSHCLTXPROVIDERCTX pCtx,
383 SHCLLISTHANDLE hList, PSHCLLISTENTRY pListEntry)
384{
385 LogFlowFuncEnter();
386
387 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
388 AssertPtr(pClient);
389
390 int rc;
391
392 PSHCLCLIENTMSG pMsg = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ,
393 VBOX_SHCL_CPARMS_LIST_ENTRY_READ);
394 if (pMsg)
395 {
396 PSHCLEVENT pEvent;
397 rc = ShClEventSourceGenerateAndRegisterEvent(&pClient->EventSrc, &pEvent);
398 if (RT_SUCCESS(rc))
399 {
400 HGCMSvcSetU64(&pMsg->aParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
401 pCtx->pTransfer->State.uID, pEvent->idEvent));
402 HGCMSvcSetU64(&pMsg->aParms[1], hList);
403 HGCMSvcSetU32(&pMsg->aParms[2], 0 /* fInfo */);
404
405 shClSvcMsgAdd(pClient, pMsg, true /* fAppend */);
406
407 rc = shClSvcClientWakeup(pClient);
408 if (RT_SUCCESS(rc))
409 {
410 PSHCLEVENTPAYLOAD pPayload;
411 rc = ShClEventWait(pEvent, pCtx->pTransfer->uTimeoutMs, &pPayload);
412 if (RT_SUCCESS(rc))
413 {
414 Assert(pPayload->cbData == sizeof(SHCLLISTENTRY));
415
416 rc = ShClTransferListEntryCopy(pListEntry, (PSHCLLISTENTRY)pPayload->pvData);
417
418 ShClPayloadFree(pPayload);
419 }
420 }
421
422 ShClEventRelease(pEvent);
423 }
424 else
425 rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
426 }
427 else
428 rc = VERR_NO_MEMORY;
429
430 LogFlowFuncLeaveRC(rc);
431 return rc;
432}
433
434DECLCALLBACK(int) shClSvcTransferIfaceListEntryWrite(PSHCLTXPROVIDERCTX pCtx,
435 SHCLLISTHANDLE hList, PSHCLLISTENTRY pListEntry)
436{
437 RT_NOREF(pCtx, hList, pListEntry);
438
439 LogFlowFuncEnter();
440
441 return VERR_NOT_IMPLEMENTED;
442}
443
444int shClSvcTransferIfaceObjOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms,
445 PSHCLOBJHANDLE phObj)
446{
447 LogFlowFuncEnter();
448
449 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
450 AssertPtr(pClient);
451
452 int rc;
453
454 PSHCLCLIENTMSG pMsg = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN,
455 VBOX_SHCL_CPARMS_OBJ_OPEN);
456 if (pMsg)
457 {
458 PSHCLEVENT pEvent;
459 rc = ShClEventSourceGenerateAndRegisterEvent(&pClient->EventSrc, &pEvent);
460 if (RT_SUCCESS(rc))
461 {
462 LogFlowFunc(("pszPath=%s, fCreate=0x%x\n", pCreateParms->pszPath, pCreateParms->fCreate));
463
464 const uint32_t cbPath = (uint32_t)strlen(pCreateParms->pszPath) + 1; /* Include terminating zero */
465
466 HGCMSvcSetU64(&pMsg->aParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
467 pCtx->pTransfer->State.uID, pEvent->idEvent));
468 HGCMSvcSetU64(&pMsg->aParms[1], 0); /* uHandle */
469 HGCMSvcSetU32(&pMsg->aParms[2], cbPath);
470 HGCMSvcSetPv (&pMsg->aParms[3], pCreateParms->pszPath, cbPath);
471 HGCMSvcSetU32(&pMsg->aParms[4], pCreateParms->fCreate);
472
473 shClSvcMsgAdd(pClient, pMsg, true /* fAppend */);
474
475 rc = shClSvcClientWakeup(pClient);
476 if (RT_SUCCESS(rc))
477 {
478 PSHCLEVENTPAYLOAD pPayload;
479 rc = ShClEventWait(pEvent, pCtx->pTransfer->uTimeoutMs, &pPayload);
480 if (RT_SUCCESS(rc))
481 {
482 Assert(pPayload->cbData == sizeof(SHCLREPLY));
483
484 PSHCLREPLY pReply = (PSHCLREPLY)pPayload->pvData;
485 AssertPtr(pReply);
486
487 Assert(pReply->uType == VBOX_SHCL_REPLYMSGTYPE_OBJ_OPEN);
488
489 LogFlowFunc(("hObj=%RU64\n", pReply->u.ObjOpen.uHandle));
490
491 *phObj = pReply->u.ObjOpen.uHandle;
492
493 ShClPayloadFree(pPayload);
494 }
495 }
496
497 ShClEventRelease(pEvent);
498 }
499 else
500 rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
501 }
502 else
503 rc = VERR_NO_MEMORY;
504
505 LogFlowFuncLeaveRC(rc);
506 return rc;
507}
508
509int shClSvcTransferIfaceObjClose(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj)
510{
511 LogFlowFuncEnter();
512
513 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
514 AssertPtr(pClient);
515
516 int rc;
517
518 PSHCLCLIENTMSG pMsg = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE,
519 VBOX_SHCL_CPARMS_OBJ_CLOSE);
520 if (pMsg)
521 {
522 PSHCLEVENT pEvent;
523 rc = ShClEventSourceGenerateAndRegisterEvent(&pClient->EventSrc, &pEvent);
524 if (RT_SUCCESS(rc))
525 {
526 HGCMSvcSetU64(&pMsg->aParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
527 pCtx->pTransfer->State.uID, pEvent->idEvent));
528 HGCMSvcSetU64(&pMsg->aParms[1], hObj);
529
530 shClSvcMsgAdd(pClient, pMsg, true /* fAppend */);
531
532 rc = shClSvcClientWakeup(pClient);
533 if (RT_SUCCESS(rc))
534 {
535 PSHCLEVENTPAYLOAD pPayload;
536 rc = ShClEventWait(pEvent, pCtx->pTransfer->uTimeoutMs, &pPayload);
537 if (RT_SUCCESS(rc))
538 {
539 Assert(pPayload->cbData == sizeof(SHCLREPLY));
540#ifdef VBOX_STRICT
541 PSHCLREPLY pReply = (PSHCLREPLY)pPayload->pvData;
542 AssertPtr(pReply);
543
544 Assert(pReply->uType == VBOX_SHCL_REPLYMSGTYPE_OBJ_CLOSE);
545
546 LogFlowFunc(("hObj=%RU64\n", pReply->u.ObjClose.uHandle));
547#endif
548 ShClPayloadFree(pPayload);
549 }
550 }
551
552 ShClEventRelease(pEvent);
553 }
554 else
555 rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
556 }
557 else
558 rc = VERR_NO_MEMORY;
559
560 LogFlowFuncLeaveRC(rc);
561 return rc;
562}
563
564int shClSvcTransferIfaceObjRead(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj,
565 void *pvData, uint32_t cbData, uint32_t fFlags, uint32_t *pcbRead)
566{
567 LogFlowFuncEnter();
568
569 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
570 AssertPtr(pClient);
571
572 int rc;
573
574 PSHCLCLIENTMSG pMsg = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ,
575 VBOX_SHCL_CPARMS_OBJ_READ_REQ);
576 if (pMsg)
577 {
578 PSHCLEVENT pEvent;
579 rc = ShClEventSourceGenerateAndRegisterEvent(&pClient->EventSrc, &pEvent);
580 if (RT_SUCCESS(rc))
581 {
582 HGCMSvcSetU64(&pMsg->aParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
583 pCtx->pTransfer->State.uID, pEvent->idEvent));
584 HGCMSvcSetU64(&pMsg->aParms[1], hObj);
585 HGCMSvcSetU32(&pMsg->aParms[2], cbData);
586 HGCMSvcSetU32(&pMsg->aParms[3], fFlags);
587
588 shClSvcMsgAdd(pClient, pMsg, true /* fAppend */);
589
590 rc = shClSvcClientWakeup(pClient);
591 if (RT_SUCCESS(rc))
592 {
593 PSHCLEVENTPAYLOAD pPayload;
594 rc = ShClEventWait(pEvent, pCtx->pTransfer->uTimeoutMs, &pPayload);
595 if (RT_SUCCESS(rc))
596 {
597 Assert(pPayload->cbData == sizeof(SHCLOBJDATACHUNK));
598
599 PSHCLOBJDATACHUNK pDataChunk = (PSHCLOBJDATACHUNK)pPayload->pvData;
600 AssertPtr(pDataChunk);
601
602 const uint32_t cbRead = RT_MIN(cbData, pDataChunk->cbData);
603
604 memcpy(pvData, pDataChunk->pvData, cbRead);
605
606 if (pcbRead)
607 *pcbRead = cbRead;
608
609 ShClPayloadFree(pPayload);
610 }
611 }
612
613 ShClEventRelease(pEvent);
614 }
615 else
616 rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
617 }
618 else
619 rc = VERR_NO_MEMORY;
620
621 LogFlowFuncLeaveRC(rc);
622 return rc;
623}
624
625int shClSvcTransferIfaceObjWrite(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj,
626 void *pvData, uint32_t cbData, uint32_t fFlags, uint32_t *pcbWritten)
627{
628 LogFlowFuncEnter();
629
630 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
631 AssertPtr(pClient);
632
633 int rc;
634
635 PSHCLCLIENTMSG pMsg = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_WRITE,
636 VBOX_SHCL_CPARMS_OBJ_WRITE);
637 if (pMsg)
638 {
639 PSHCLEVENT pEvent;
640 rc = ShClEventSourceGenerateAndRegisterEvent(&pClient->EventSrc, &pEvent);
641 if (RT_SUCCESS(rc))
642 {
643 HGCMSvcSetU64(&pMsg->aParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
644 pCtx->pTransfer->State.uID, pEvent->idEvent));
645 HGCMSvcSetU64(&pMsg->aParms[1], hObj);
646 HGCMSvcSetU64(&pMsg->aParms[2], cbData);
647 HGCMSvcSetU64(&pMsg->aParms[3], fFlags);
648
649 shClSvcMsgAdd(pClient, pMsg, true /* fAppend */);
650
651 rc = shClSvcClientWakeup(pClient);
652 if (RT_SUCCESS(rc))
653 {
654 PSHCLEVENTPAYLOAD pPayload;
655 rc = ShClEventWait(pEvent, pCtx->pTransfer->uTimeoutMs, &pPayload);
656 if (RT_SUCCESS(rc))
657 {
658 const uint32_t cbRead = RT_MIN(cbData, pPayload->cbData);
659
660 memcpy(pvData, pPayload->pvData, cbRead);
661
662 if (pcbWritten)
663 *pcbWritten = cbRead;
664
665 ShClPayloadFree(pPayload);
666 }
667 }
668
669 ShClEventRelease(pEvent);
670 }
671 else
672 rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
673 }
674 else
675 rc = VERR_NO_MEMORY;
676
677 LogFlowFuncLeaveRC(rc);
678 return rc;
679}
680
681
682/*********************************************************************************************************************************
683* HGCM getters / setters *
684*********************************************************************************************************************************/
685
686/**
687 * Returns whether a HGCM message is allowed in a certain service mode or not.
688 *
689 * @returns \c true if message is allowed, \c false if not.
690 * @param uMode Service mode to check allowance for.
691 * @param uMsg HGCM message to check allowance for.
692 */
693bool shClSvcTransferMsgIsAllowed(uint32_t uMode, uint32_t uMsg)
694{
695 const bool fHostToGuest = uMode == VBOX_SHCL_MODE_HOST_TO_GUEST
696 || uMode == VBOX_SHCL_MODE_BIDIRECTIONAL;
697
698 const bool fGuestToHost = uMode == VBOX_SHCL_MODE_GUEST_TO_HOST
699 || uMode == VBOX_SHCL_MODE_BIDIRECTIONAL;
700
701 bool fAllowed = false; /* If in doubt, don't allow. */
702
703 switch (uMsg)
704 {
705 case VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_WRITE:
706 RT_FALL_THROUGH();
707 case VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_WRITE:
708 RT_FALL_THROUGH();
709 case VBOX_SHCL_GUEST_FN_LIST_HDR_WRITE:
710 RT_FALL_THROUGH();
711 case VBOX_SHCL_GUEST_FN_LIST_ENTRY_WRITE:
712 RT_FALL_THROUGH();
713 case VBOX_SHCL_GUEST_FN_OBJ_WRITE:
714 fAllowed = fGuestToHost;
715 break;
716
717 case VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_READ:
718 RT_FALL_THROUGH();
719 case VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_READ:
720 RT_FALL_THROUGH();
721 case VBOX_SHCL_GUEST_FN_LIST_HDR_READ:
722 RT_FALL_THROUGH();
723 case VBOX_SHCL_GUEST_FN_LIST_ENTRY_READ:
724 RT_FALL_THROUGH();
725 case VBOX_SHCL_GUEST_FN_OBJ_READ:
726 fAllowed = fHostToGuest;
727 break;
728
729 case VBOX_SHCL_GUEST_FN_CONNECT:
730 RT_FALL_THROUGH();
731 case VBOX_SHCL_GUEST_FN_NEGOTIATE_CHUNK_SIZE:
732 RT_FALL_THROUGH();
733 case VBOX_SHCL_GUEST_FN_MSG_PEEK_WAIT:
734 RT_FALL_THROUGH();
735 case VBOX_SHCL_GUEST_FN_MSG_PEEK_NOWAIT:
736 RT_FALL_THROUGH();
737 case VBOX_SHCL_GUEST_FN_REPORT_FEATURES:
738 RT_FALL_THROUGH();
739 case VBOX_SHCL_GUEST_FN_QUERY_FEATURES:
740 RT_FALL_THROUGH();
741 case VBOX_SHCL_GUEST_FN_MSG_GET:
742 RT_FALL_THROUGH();
743 case VBOX_SHCL_GUEST_FN_REPLY:
744 RT_FALL_THROUGH();
745 case VBOX_SHCL_GUEST_FN_MSG_CANCEL:
746 RT_FALL_THROUGH();
747 case VBOX_SHCL_GUEST_FN_ERROR:
748 RT_FALL_THROUGH();
749 case VBOX_SHCL_GUEST_FN_LIST_OPEN:
750 RT_FALL_THROUGH();
751 case VBOX_SHCL_GUEST_FN_LIST_CLOSE:
752 RT_FALL_THROUGH();
753 case VBOX_SHCL_GUEST_FN_OBJ_OPEN:
754 RT_FALL_THROUGH();
755 case VBOX_SHCL_GUEST_FN_OBJ_CLOSE:
756 fAllowed = fHostToGuest || fGuestToHost;
757 break;
758
759 default:
760 break;
761 }
762
763 LogFlowFunc(("uMsg=%RU32 (%s), uMode=%RU32 -> fAllowed=%RTbool\n", uMsg, ShClGuestMsgToStr(uMsg), uMode, fAllowed));
764 return fAllowed;
765}
766
767/**
768 * Gets a transfer message reply from HGCM service parameters.
769 *
770 * @returns VBox status code.
771 * @param cParms Number of HGCM parameters supplied in \a aParms.
772 * @param aParms Array of HGCM parameters.
773 * @param pReply Where to store the reply.
774 */
775static int shClSvcTransferGetReply(uint32_t cParms, VBOXHGCMSVCPARM aParms[],
776 PSHCLREPLY pReply)
777{
778 int rc;
779
780 if (cParms >= VBOX_SHCL_CPARMS_REPLY_MIN)
781 {
782 /* aParms[0] has the context ID. */
783 rc = HGCMSvcGetU32(&aParms[1], &pReply->uType);
784 if (RT_SUCCESS(rc))
785 rc = HGCMSvcGetU32(&aParms[2], &pReply->rc);
786 if (RT_SUCCESS(rc))
787 rc = HGCMSvcGetPv(&aParms[3], &pReply->pvPayload, &pReply->cbPayload);
788
789 if (RT_SUCCESS(rc))
790 {
791 rc = VERR_INVALID_PARAMETER; /* Play safe. */
792
793 const unsigned idxParm = VBOX_SHCL_CPARMS_REPLY_MIN;
794
795 switch (pReply->uType)
796 {
797 case VBOX_SHCL_REPLYMSGTYPE_TRANSFER_STATUS:
798 {
799 if (cParms > idxParm)
800 rc = HGCMSvcGetU32(&aParms[idxParm], &pReply->u.TransferStatus.uStatus);
801
802 LogFlowFunc(("uTransferStatus=%RU32\n", pReply->u.TransferStatus.uStatus));
803 break;
804 }
805
806 case VBOX_SHCL_REPLYMSGTYPE_LIST_OPEN:
807 {
808 if (cParms > idxParm)
809 rc = HGCMSvcGetU64(&aParms[idxParm], &pReply->u.ListOpen.uHandle);
810
811 LogFlowFunc(("hListOpen=%RU64\n", pReply->u.ListOpen.uHandle));
812 break;
813 }
814
815 case VBOX_SHCL_REPLYMSGTYPE_LIST_CLOSE:
816 {
817 if (cParms > idxParm)
818 rc = HGCMSvcGetU64(&aParms[idxParm], &pReply->u.ListClose.uHandle);
819
820 LogFlowFunc(("hListClose=%RU64\n", pReply->u.ListClose.uHandle));
821 break;
822 }
823
824 case VBOX_SHCL_REPLYMSGTYPE_OBJ_OPEN:
825 {
826 if (cParms > idxParm)
827 rc = HGCMSvcGetU64(&aParms[idxParm], &pReply->u.ObjOpen.uHandle);
828
829 LogFlowFunc(("hObjOpen=%RU64\n", pReply->u.ObjOpen.uHandle));
830 break;
831 }
832
833 case VBOX_SHCL_REPLYMSGTYPE_OBJ_CLOSE:
834 {
835 if (cParms > idxParm)
836 rc = HGCMSvcGetU64(&aParms[idxParm], &pReply->u.ObjClose.uHandle);
837
838 LogFlowFunc(("hObjClose=%RU64\n", pReply->u.ObjClose.uHandle));
839 break;
840 }
841
842 default:
843 rc = VERR_NOT_SUPPORTED;
844 break;
845 }
846 }
847 }
848 else
849 rc = VERR_INVALID_PARAMETER;
850
851 LogFlowFuncLeaveRC(rc);
852 return rc;
853}
854
855/**
856 * Gets a transfer root list header from HGCM service parameters.
857 *
858 * @returns VBox status code.
859 * @param cParms Number of HGCM parameters supplied in \a aParms.
860 * @param aParms Array of HGCM parameters.
861 * @param pRootLstHdr Where to store the transfer root list header on success.
862 */
863static int shClSvcTransferGetRootListHdr(uint32_t cParms, VBOXHGCMSVCPARM aParms[],
864 PSHCLROOTLISTHDR pRootLstHdr)
865{
866 int rc;
867
868 if (cParms == VBOX_SHCL_CPARMS_ROOT_LIST_HDR_WRITE)
869 {
870 rc = HGCMSvcGetU32(&aParms[1], &pRootLstHdr->fRoots);
871 if (RT_SUCCESS(rc))
872 rc = HGCMSvcGetU32(&aParms[2], &pRootLstHdr->cRoots);
873 }
874 else
875 rc = VERR_INVALID_PARAMETER;
876
877 LogFlowFuncLeaveRC(rc);
878 return rc;
879}
880
881/**
882 * Gets a transfer root list entry from HGCM service parameters.
883 *
884 * @returns VBox status code.
885 * @param cParms Number of HGCM parameters supplied in \a aParms.
886 * @param aParms Array of HGCM parameters.
887 * @param pListEntry Where to store the root list entry.
888 */
889static int shClSvcTransferGetRootListEntry(uint32_t cParms, VBOXHGCMSVCPARM aParms[],
890 PSHCLROOTLISTENTRY pListEntry)
891{
892 int rc;
893
894 if (cParms == VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_WRITE)
895 {
896 rc = HGCMSvcGetU32(&aParms[1], &pListEntry->fInfo);
897 /* Note: aParms[2] contains the entry index, currently being ignored. */
898 if (RT_SUCCESS(rc))
899 rc = HGCMSvcGetPv(&aParms[3], (void **)&pListEntry->pszName, &pListEntry->cbName);
900 if (RT_SUCCESS(rc))
901 {
902 uint32_t cbInfo;
903 rc = HGCMSvcGetU32(&aParms[4], &cbInfo);
904 if (RT_SUCCESS(rc))
905 {
906 rc = HGCMSvcGetPv(&aParms[5], &pListEntry->pvInfo, &pListEntry->cbInfo);
907 AssertReturn(cbInfo == pListEntry->cbInfo, VERR_INVALID_PARAMETER);
908 }
909 }
910 }
911 else
912 rc = VERR_INVALID_PARAMETER;
913
914 LogFlowFuncLeaveRC(rc);
915 return rc;
916}
917
918/**
919 * Gets a transfer list open request from HGCM service parameters.
920 *
921 * @returns VBox status code.
922 * @param cParms Number of HGCM parameters supplied in \a aParms.
923 * @param aParms Array of HGCM parameters.
924 * @param pOpenParms Where to store the open parameters of the request.
925 */
926static int shClSvcTransferGetListOpen(uint32_t cParms, VBOXHGCMSVCPARM aParms[],
927 PSHCLLISTOPENPARMS pOpenParms)
928{
929 int rc;
930
931 if (cParms == VBOX_SHCL_CPARMS_LIST_OPEN)
932 {
933 rc = HGCMSvcGetU32(&aParms[1], &pOpenParms->fList);
934 if (RT_SUCCESS(rc))
935 rc = HGCMSvcGetStr(&aParms[2], &pOpenParms->pszFilter, &pOpenParms->cbFilter);
936 if (RT_SUCCESS(rc))
937 rc = HGCMSvcGetStr(&aParms[3], &pOpenParms->pszPath, &pOpenParms->cbPath);
938
939 /** @todo Some more validation. */
940 }
941 else
942 rc = VERR_INVALID_PARAMETER;
943
944 LogFlowFuncLeaveRC(rc);
945 return rc;
946}
947
948/**
949 * Sets a transfer list open request to HGCM service parameters.
950 *
951 * @returns VBox status code.
952 * @param cParms Number of HGCM parameters supplied in \a aParms.
953 * @param aParms Array of HGCM parameters.
954 * @param idCtx Context ID to use.
955 * @param pOpenParms List open parameters to set.
956 */
957static int shClSvcTransferSetListOpen(uint32_t cParms, VBOXHGCMSVCPARM aParms[],
958 uint64_t idCtx, PSHCLLISTOPENPARMS pOpenParms)
959{
960 int rc;
961
962 if (cParms == VBOX_SHCL_CPARMS_LIST_OPEN)
963 {
964 HGCMSvcSetU64(&aParms[0], idCtx);
965 HGCMSvcSetU32(&aParms[1], pOpenParms->fList);
966 HGCMSvcSetPv (&aParms[2], pOpenParms->pszFilter, pOpenParms->cbFilter);
967 HGCMSvcSetPv (&aParms[3], pOpenParms->pszPath, pOpenParms->cbPath);
968 HGCMSvcSetU64(&aParms[4], 0); /* OUT: uHandle */
969
970 rc = VINF_SUCCESS;
971 }
972 else
973 rc = VERR_INVALID_PARAMETER;
974
975 LogFlowFuncLeaveRC(rc);
976 return rc;
977}
978
979/**
980 * Sets a transfer list close request to HGCM service parameters.
981 *
982 * @returns VBox status code.
983 * @param cParms Number of HGCM parameters supplied in \a aParms.
984 * @param aParms Array of HGCM parameters.
985 * @param idCtx Context ID to use.
986 * @param hList Handle of list to close.
987 */
988static int shClSvcTransferSetListClose(uint32_t cParms, VBOXHGCMSVCPARM aParms[],
989 uint64_t idCtx, SHCLLISTHANDLE hList)
990{
991 int rc;
992
993 if (cParms == VBOX_SHCL_CPARMS_LIST_CLOSE)
994 {
995 HGCMSvcSetU64(&aParms[0], idCtx);
996 HGCMSvcSetU64(&aParms[1], hList);
997
998 rc = VINF_SUCCESS;
999 }
1000 else
1001 rc = VERR_INVALID_PARAMETER;
1002
1003 LogFlowFuncLeaveRC(rc);
1004 return rc;
1005}
1006
1007/**
1008 * Gets a transfer list header from HGCM service parameters.
1009 *
1010 * @returns VBox status code.
1011 * @param cParms Number of HGCM parameters supplied in \a aParms.
1012 * @param aParms Array of HGCM parameters.
1013 * @param phList Where to store the list handle.
1014 * @param pListHdr Where to store the list header.
1015 */
1016static int shClSvcTransferGetListHdr(uint32_t cParms, VBOXHGCMSVCPARM aParms[],
1017 PSHCLLISTHANDLE phList, PSHCLLISTHDR pListHdr)
1018{
1019 int rc;
1020
1021 if (cParms == VBOX_SHCL_CPARMS_LIST_HDR)
1022 {
1023 rc = HGCMSvcGetU64(&aParms[1], phList);
1024 /* Note: Flags (aParms[2]) not used here. */
1025 if (RT_SUCCESS(rc))
1026 rc = HGCMSvcGetU32(&aParms[3], &pListHdr->fFeatures);
1027 if (RT_SUCCESS(rc))
1028 rc = HGCMSvcGetU64(&aParms[4], &pListHdr->cTotalObjects);
1029 if (RT_SUCCESS(rc))
1030 rc = HGCMSvcGetU64(&aParms[5], &pListHdr->cbTotalSize);
1031
1032 if (RT_SUCCESS(rc))
1033 {
1034 /** @todo Validate pvMetaFmt + cbMetaFmt. */
1035 /** @todo Validate header checksum. */
1036 }
1037 }
1038 else
1039 rc = VERR_INVALID_PARAMETER;
1040
1041 LogFlowFuncLeaveRC(rc);
1042 return rc;
1043}
1044
1045/**
1046 * Sets a transfer list header to HGCM service parameters.
1047 *
1048 * @returns VBox status code.
1049 * @param cParms Number of HGCM parameters supplied in \a aParms.
1050 * @param aParms Array of HGCM parameters.
1051 * @param pListHdr Pointer to list header to set.
1052 */
1053static int shClSvcTransferSetListHdr(uint32_t cParms, VBOXHGCMSVCPARM aParms[], PSHCLLISTHDR pListHdr)
1054{
1055 int rc;
1056
1057 if (cParms == VBOX_SHCL_CPARMS_LIST_HDR)
1058 {
1059 /** @todo Set pvMetaFmt + cbMetaFmt. */
1060 /** @todo Calculate header checksum. */
1061
1062 HGCMSvcSetU32(&aParms[3], pListHdr->fFeatures);
1063 HGCMSvcSetU64(&aParms[4], pListHdr->cTotalObjects);
1064 HGCMSvcSetU64(&aParms[5], pListHdr->cbTotalSize);
1065
1066 rc = VINF_SUCCESS;
1067 }
1068 else
1069 rc = VERR_INVALID_PARAMETER;
1070
1071 LogFlowFuncLeaveRC(rc);
1072 return rc;
1073}
1074
1075/**
1076 * Gets a transfer list entry from HGCM service parameters.
1077 *
1078 * @returns VBox status code.
1079 * @param cParms Number of HGCM parameters supplied in \a aParms.
1080 * @param aParms Array of HGCM parameters.
1081 * @param phList Where to store the list handle.
1082 * @param pListEntry Where to store the list entry.
1083 */
1084static int shClSvcTransferGetListEntry(uint32_t cParms, VBOXHGCMSVCPARM aParms[],
1085 PSHCLLISTHANDLE phList, PSHCLLISTENTRY pListEntry)
1086{
1087 int rc;
1088
1089 if (cParms == VBOX_SHCL_CPARMS_LIST_ENTRY)
1090 {
1091 rc = HGCMSvcGetU64(&aParms[1], phList);
1092 if (RT_SUCCESS(rc))
1093 rc = HGCMSvcGetU32(&aParms[2], &pListEntry->fInfo);
1094 if (RT_SUCCESS(rc))
1095 rc = HGCMSvcGetPv(&aParms[3], (void **)&pListEntry->pszName, &pListEntry->cbName);
1096 if (RT_SUCCESS(rc))
1097 {
1098 uint32_t cbInfo;
1099 rc = HGCMSvcGetU32(&aParms[4], &cbInfo);
1100 if (RT_SUCCESS(rc))
1101 {
1102 rc = HGCMSvcGetPv(&aParms[5], &pListEntry->pvInfo, &pListEntry->cbInfo);
1103 AssertReturn(cbInfo == pListEntry->cbInfo, VERR_INVALID_PARAMETER);
1104 }
1105 }
1106
1107 if (RT_SUCCESS(rc))
1108 {
1109 if (!ShClTransferListEntryIsValid(pListEntry))
1110 rc = VERR_INVALID_PARAMETER;
1111 }
1112 }
1113 else
1114 rc = VERR_INVALID_PARAMETER;
1115
1116 LogFlowFuncLeaveRC(rc);
1117 return rc;
1118}
1119
1120/**
1121 * Sets a Shared Clipboard list entry to HGCM service parameters.
1122 *
1123 * @returns VBox status code.
1124 * @param cParms Number of HGCM parameters supplied in \a aParms.
1125 * @param aParms Array of HGCM parameters.
1126 * @param pListEntry Pointer list entry to set.
1127 */
1128static int shClSvcTransferSetListEntry(uint32_t cParms, VBOXHGCMSVCPARM aParms[],
1129 PSHCLLISTENTRY pListEntry)
1130{
1131 int rc;
1132
1133 /* Sanity. */
1134 AssertReturn(ShClTransferListEntryIsValid(pListEntry), VERR_INVALID_PARAMETER);
1135
1136 if (cParms == VBOX_SHCL_CPARMS_LIST_ENTRY)
1137 {
1138 HGCMSvcSetPv (&aParms[3], pListEntry->pszName, pListEntry->cbName);
1139 HGCMSvcSetU32(&aParms[4], pListEntry->cbInfo);
1140 HGCMSvcSetPv (&aParms[5], pListEntry->pvInfo, pListEntry->cbInfo);
1141
1142 rc = VINF_SUCCESS;
1143 }
1144 else
1145 rc = VERR_INVALID_PARAMETER;
1146
1147 LogFlowFuncLeaveRC(rc);
1148 return rc;
1149}
1150
1151/**
1152 * Gets a transfer object data chunk from HGCM service parameters.
1153 *
1154 * @returns VBox status code.
1155 * @param cParms Number of HGCM parameters supplied in \a aParms.
1156 * @param aParms Array of HGCM parameters.
1157 * @param pDataChunk Where to store the object data chunk data.
1158 */
1159static int shClSvcTransferGetObjDataChunk(uint32_t cParms, VBOXHGCMSVCPARM aParms[], PSHCLOBJDATACHUNK pDataChunk)
1160{
1161 AssertPtrReturn(aParms, VERR_INVALID_PARAMETER);
1162 AssertPtrReturn(pDataChunk, VERR_INVALID_PARAMETER);
1163
1164 int rc;
1165
1166 if (cParms == VBOX_SHCL_CPARMS_OBJ_WRITE)
1167 {
1168 rc = HGCMSvcGetU64(&aParms[1], &pDataChunk->uHandle);
1169 if (RT_SUCCESS(rc))
1170 {
1171 uint32_t cbData;
1172 rc = HGCMSvcGetU32(&aParms[2], &cbData);
1173 if (RT_SUCCESS(rc))
1174 {
1175 rc = HGCMSvcGetPv(&aParms[3], &pDataChunk->pvData, &pDataChunk->cbData);
1176 AssertReturn(cbData == pDataChunk->cbData, VERR_INVALID_PARAMETER);
1177
1178 /** @todo Implement checksum handling. */
1179 }
1180 }
1181 }
1182 else
1183 rc = VERR_INVALID_PARAMETER;
1184
1185 LogFlowFuncLeaveRC(rc);
1186 return rc;
1187}
1188
1189/**
1190 * Handles a guest reply (VBOX_SHCL_GUEST_FN_REPLY) message.
1191 *
1192 * @returns VBox status code.
1193 * @param pClient Pointer to associated client.
1194 * @param pTransfer Pointer to transfer to handle guest reply for.
1195 * @param cParms Number of function parameters supplied.
1196 * @param aParms Array function parameters supplied.
1197 */
1198static int shClSvcTransferHandleReply(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer,
1199 uint32_t cParms, VBOXHGCMSVCPARM aParms[])
1200{
1201 RT_NOREF(pClient, pTransfer);
1202
1203 int rc;
1204
1205 uint32_t cbReply = sizeof(SHCLREPLY);
1206 PSHCLREPLY pReply = (PSHCLREPLY)RTMemAlloc(cbReply);
1207 if (pReply)
1208 {
1209 rc = shClSvcTransferGetReply(cParms, aParms, pReply);
1210 if (RT_SUCCESS(rc))
1211 {
1212 PSHCLEVENTPAYLOAD pPayload
1213 = (PSHCLEVENTPAYLOAD)RTMemAlloc(sizeof(SHCLEVENTPAYLOAD));
1214 if (pPayload)
1215 {
1216 pPayload->pvData = pReply;
1217 pPayload->cbData = cbReply;
1218
1219 switch (pReply->uType)
1220 {
1221 case VBOX_SHCL_REPLYMSGTYPE_TRANSFER_STATUS:
1222 RT_FALL_THROUGH();
1223 case VBOX_SHCL_REPLYMSGTYPE_LIST_OPEN:
1224 RT_FALL_THROUGH();
1225 case VBOX_SHCL_REPLYMSGTYPE_LIST_CLOSE:
1226 RT_FALL_THROUGH();
1227 case VBOX_SHCL_REPLYMSGTYPE_OBJ_OPEN:
1228 RT_FALL_THROUGH();
1229 case VBOX_SHCL_REPLYMSGTYPE_OBJ_CLOSE:
1230 {
1231 uint64_t uCID;
1232 rc = HGCMSvcGetU64(&aParms[0], &uCID);
1233 if (RT_SUCCESS(rc))
1234 {
1235 const PSHCLEVENT pEvent
1236 = ShClEventSourceGetFromId(&pClient->EventSrc, VBOX_SHCL_CONTEXTID_GET_EVENT(uCID));
1237 if (pEvent)
1238 {
1239 LogFlowFunc(("uCID=%RU64 -> idEvent=%RU32\n", uCID, pEvent->idEvent));
1240
1241 rc = ShClEventSignal(pEvent, pPayload);
1242 }
1243 /** @todo Silently skip? */
1244 }
1245 break;
1246 }
1247
1248 default:
1249 rc = VERR_NOT_FOUND;
1250 break;
1251 }
1252
1253 if (RT_FAILURE(rc))
1254 {
1255 if (pPayload)
1256 RTMemFree(pPayload);
1257 }
1258 }
1259 else
1260 rc = VERR_NO_MEMORY;
1261 }
1262 }
1263 else
1264 rc = VERR_NO_MEMORY;
1265
1266 if (RT_FAILURE(rc))
1267 {
1268 if (pReply)
1269 RTMemFree(pReply);
1270 }
1271
1272 LogFlowFuncLeaveRC(rc);
1273 return rc;
1274}
1275
1276/**
1277 * Transfer client (guest) handler for the Shared Clipboard host service.
1278 *
1279 * @returns VBox status code, or VINF_HGCM_ASYNC_EXECUTE if returning to the client will be deferred.
1280 * @param pClient Pointer to associated client.
1281 * @param callHandle The client's call handle of this call.
1282 * @param u32Function Function number being called.
1283 * @param cParms Number of function parameters supplied.
1284 * @param aParms Array function parameters supplied.
1285 * @param tsArrival Timestamp of arrival.
1286 */
1287int shClSvcTransferHandler(PSHCLCLIENT pClient,
1288 VBOXHGCMCALLHANDLE callHandle,
1289 uint32_t u32Function,
1290 uint32_t cParms,
1291 VBOXHGCMSVCPARM aParms[],
1292 uint64_t tsArrival)
1293{
1294 RT_NOREF(callHandle, aParms, tsArrival);
1295
1296 LogFlowFunc(("uClient=%RU32, u32Function=%RU32 (%s), cParms=%RU32, g_ExtState.pfnExtension=%p\n",
1297 pClient->State.uClientID, u32Function, ShClGuestMsgToStr(u32Function), cParms, g_ExtState.pfnExtension));
1298
1299 /* Check if we've the right mode set. */
1300 if (!shClSvcTransferMsgIsAllowed(ShClSvcGetMode(), u32Function))
1301 {
1302 LogFunc(("Wrong clipboard mode, denying access\n"));
1303 return VERR_ACCESS_DENIED;
1304 }
1305
1306 int rc = VERR_INVALID_PARAMETER; /* Play safe by default. */
1307
1308 /*
1309 * Pre-check: For certain messages we need to make sure that a (right) transfer is present.
1310 */
1311 uint64_t uCID = 0; /* Context ID */
1312 PSHCLTRANSFER pTransfer = NULL;
1313
1314 switch (u32Function)
1315 {
1316 default:
1317 {
1318 if (!ShClTransferCtxGetTotalTransfers(&pClient->Transfers.Ctx))
1319 {
1320 LogFunc(("No transfers found\n"));
1321 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
1322 break;
1323 }
1324
1325 if (cParms < 1)
1326 break;
1327
1328 rc = HGCMSvcGetU64(&aParms[0], &uCID);
1329 if (RT_FAILURE(rc))
1330 break;
1331
1332 const SHCLTRANSFERID uTransferID = VBOX_SHCL_CONTEXTID_GET_TRANSFER(uCID);
1333
1334 pTransfer = ShClTransferCtxGetTransferById(&pClient->Transfers.Ctx, uTransferID);
1335 if (!pTransfer)
1336 {
1337 LogFunc(("Transfer with ID %RU16 not found\n", uTransferID));
1338 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
1339 }
1340 break;
1341 }
1342 }
1343
1344 if (RT_FAILURE(rc))
1345 return rc;
1346
1347 rc = VERR_INVALID_PARAMETER; /* Play safe. */
1348
1349 switch (u32Function)
1350 {
1351 case VBOX_SHCL_GUEST_FN_REPLY:
1352 {
1353 rc = shClSvcTransferHandleReply(pClient, pTransfer, cParms, aParms);
1354 break;
1355 }
1356
1357 case VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_READ:
1358 {
1359 if (cParms != VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ)
1360 break;
1361
1362 if ( ShClTransferGetSource(pTransfer) == SHCLSOURCE_LOCAL
1363 && ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_TO_REMOTE)
1364 {
1365 /* Get roots if this is a local write transfer (host -> guest). */
1366 rc = ShClBackendTransferGetRoots(pClient->pBackend, pClient, pTransfer);
1367 }
1368 else
1369 {
1370 rc = VERR_INVALID_PARAMETER;
1371 break;
1372 }
1373
1374 SHCLROOTLISTHDR rootListHdr;
1375 RT_ZERO(rootListHdr);
1376
1377 rootListHdr.cRoots = ShClTransferRootsCount(pTransfer);
1378
1379 HGCMSvcSetU64(&aParms[0], 0 /* Context ID */);
1380 HGCMSvcSetU32(&aParms[1], rootListHdr.fRoots);
1381 HGCMSvcSetU32(&aParms[2], rootListHdr.cRoots);
1382
1383 rc = VINF_SUCCESS;
1384 break;
1385 }
1386
1387 case VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_WRITE:
1388 {
1389 SHCLROOTLISTHDR lstHdr;
1390 rc = shClSvcTransferGetRootListHdr(cParms, aParms, &lstHdr);
1391 if (RT_SUCCESS(rc))
1392 {
1393 void *pvData = ShClTransferRootListHdrDup(&lstHdr);
1394 uint32_t cbData = sizeof(SHCLROOTLISTHDR);
1395
1396 const PSHCLEVENT pEvent = ShClEventSourceGetFromId(&pClient->EventSrc, VBOX_SHCL_CONTEXTID_GET_EVENT(uCID));
1397 if (pEvent)
1398 {
1399 PSHCLEVENTPAYLOAD pPayload;
1400 rc = ShClPayloadAlloc(pEvent->idEvent, pvData, cbData, &pPayload);
1401 if (RT_SUCCESS(rc))
1402 {
1403 rc = ShClEventSignal(pEvent, pPayload);
1404 if (RT_FAILURE(rc))
1405 ShClPayloadFree(pPayload);
1406 }
1407 }
1408 else
1409 rc = VERR_SHCLPB_EVENT_ID_NOT_FOUND;
1410 }
1411 break;
1412 }
1413
1414 case VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_READ:
1415 {
1416 if (cParms != VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ)
1417 break;
1418
1419 /* aParms[1] contains fInfo flags, currently unused. */
1420 uint32_t uIndex;
1421 rc = HGCMSvcGetU32(&aParms[2], &uIndex);
1422 if (RT_SUCCESS(rc))
1423 {
1424 SHCLROOTLISTENTRY rootListEntry;
1425 rc = ShClTransferRootsEntry(pTransfer, uIndex, &rootListEntry);
1426 if (RT_SUCCESS(rc))
1427 {
1428 HGCMSvcSetPv (&aParms[3], rootListEntry.pszName, rootListEntry.cbName);
1429 HGCMSvcSetU32(&aParms[4], rootListEntry.cbInfo);
1430 HGCMSvcSetPv (&aParms[5], rootListEntry.pvInfo, rootListEntry.cbInfo);
1431 }
1432 }
1433 break;
1434 }
1435
1436 case VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_WRITE:
1437 {
1438 SHCLROOTLISTENTRY lstEntry;
1439 rc = shClSvcTransferGetRootListEntry(cParms, aParms, &lstEntry);
1440 if (RT_SUCCESS(rc))
1441 {
1442 void *pvData = ShClTransferRootListEntryDup(&lstEntry);
1443 uint32_t cbData = sizeof(SHCLROOTLISTENTRY);
1444
1445 const PSHCLEVENT pEvent = ShClEventSourceGetFromId(&pClient->EventSrc, VBOX_SHCL_CONTEXTID_GET_EVENT(uCID));
1446 if (pEvent)
1447 {
1448 PSHCLEVENTPAYLOAD pPayload;
1449 rc = ShClPayloadAlloc(pEvent->idEvent, pvData, cbData, &pPayload);
1450 if (RT_SUCCESS(rc))
1451 {
1452 rc = ShClEventSignal(pEvent, pPayload);
1453 if (RT_FAILURE(rc))
1454 ShClPayloadFree(pPayload);
1455 }
1456 }
1457 else
1458 rc = VERR_SHCLPB_EVENT_ID_NOT_FOUND;
1459 }
1460 break;
1461 }
1462
1463 case VBOX_SHCL_GUEST_FN_LIST_OPEN:
1464 {
1465 SHCLLISTOPENPARMS listOpenParms;
1466 rc = shClSvcTransferGetListOpen(cParms, aParms, &listOpenParms);
1467 if (RT_SUCCESS(rc))
1468 {
1469 SHCLLISTHANDLE hList;
1470 rc = ShClTransferListOpen(pTransfer, &listOpenParms, &hList);
1471 if (RT_SUCCESS(rc))
1472 {
1473 /* Return list handle. */
1474 HGCMSvcSetU64(&aParms[6], hList);
1475 }
1476 }
1477 break;
1478 }
1479
1480 case VBOX_SHCL_GUEST_FN_LIST_CLOSE:
1481 {
1482 if (cParms != VBOX_SHCL_CPARMS_LIST_CLOSE)
1483 break;
1484
1485 SHCLLISTHANDLE hList;
1486 rc = HGCMSvcGetU64(&aParms[1], &hList);
1487 if (RT_SUCCESS(rc))
1488 {
1489 rc = ShClTransferListClose(pTransfer, hList);
1490 }
1491 break;
1492 }
1493
1494 case VBOX_SHCL_GUEST_FN_LIST_HDR_READ:
1495 {
1496 if (cParms != VBOX_SHCL_CPARMS_LIST_HDR)
1497 break;
1498
1499 SHCLLISTHANDLE hList;
1500 rc = HGCMSvcGetU64(&aParms[1], &hList); /* Get list handle. */
1501 if (RT_SUCCESS(rc))
1502 {
1503 SHCLLISTHDR hdrList;
1504 rc = ShClTransferListGetHeader(pTransfer, hList, &hdrList);
1505 if (RT_SUCCESS(rc))
1506 rc = shClSvcTransferSetListHdr(cParms, aParms, &hdrList);
1507 }
1508 break;
1509 }
1510
1511 case VBOX_SHCL_GUEST_FN_LIST_HDR_WRITE:
1512 {
1513 SHCLLISTHDR hdrList;
1514 rc = ShClTransferListHdrInit(&hdrList);
1515 if (RT_SUCCESS(rc))
1516 {
1517 SHCLLISTHANDLE hList;
1518 rc = shClSvcTransferGetListHdr(cParms, aParms, &hList, &hdrList);
1519 if (RT_SUCCESS(rc))
1520 {
1521 void *pvData = ShClTransferListHdrDup(&hdrList);
1522 uint32_t cbData = sizeof(SHCLLISTHDR);
1523
1524 const PSHCLEVENT pEvent = ShClEventSourceGetFromId(&pClient->EventSrc, VBOX_SHCL_CONTEXTID_GET_EVENT(uCID));
1525 if (pEvent)
1526 {
1527 PSHCLEVENTPAYLOAD pPayload;
1528 rc = ShClPayloadAlloc(pEvent->idEvent, pvData, cbData, &pPayload);
1529 if (RT_SUCCESS(rc))
1530 {
1531 rc = ShClEventSignal(pEvent, pPayload);
1532 if (RT_FAILURE(rc))
1533 ShClPayloadFree(pPayload);
1534 }
1535 }
1536 else
1537 rc = VERR_SHCLPB_EVENT_ID_NOT_FOUND;
1538 }
1539 }
1540 break;
1541 }
1542
1543 case VBOX_SHCL_GUEST_FN_LIST_ENTRY_READ:
1544 {
1545 if (cParms != VBOX_SHCL_CPARMS_LIST_ENTRY)
1546 break;
1547
1548 SHCLLISTHANDLE hList;
1549 rc = HGCMSvcGetU64(&aParms[1], &hList); /* Get list handle. */
1550 if (RT_SUCCESS(rc))
1551 {
1552 SHCLLISTENTRY entryList;
1553 rc = ShClTransferListEntryInit(&entryList);
1554 if (RT_SUCCESS(rc))
1555 {
1556 rc = ShClTransferListRead(pTransfer, hList, &entryList);
1557 if (RT_SUCCESS(rc))
1558 rc = shClSvcTransferSetListEntry(cParms, aParms, &entryList);
1559 }
1560 }
1561 break;
1562 }
1563
1564 case VBOX_SHCL_GUEST_FN_LIST_ENTRY_WRITE:
1565 {
1566 SHCLLISTENTRY entryList;
1567 rc = ShClTransferListEntryInit(&entryList);
1568 if (RT_SUCCESS(rc))
1569 {
1570 SHCLLISTHANDLE hList;
1571 rc = shClSvcTransferGetListEntry(cParms, aParms, &hList, &entryList);
1572 if (RT_SUCCESS(rc))
1573 {
1574 void *pvData = ShClTransferListEntryDup(&entryList);
1575 uint32_t cbData = sizeof(SHCLLISTENTRY);
1576
1577 const PSHCLEVENT pEvent = ShClEventSourceGetFromId(&pClient->EventSrc, VBOX_SHCL_CONTEXTID_GET_EVENT(uCID));
1578 if (pEvent)
1579 {
1580 PSHCLEVENTPAYLOAD pPayload;
1581 rc = ShClPayloadAlloc(pEvent->idEvent, pvData, cbData, &pPayload);
1582 if (RT_SUCCESS(rc))
1583 {
1584 rc = ShClEventSignal(pEvent, pPayload);
1585 if (RT_FAILURE(rc))
1586 ShClPayloadFree(pPayload);
1587 }
1588 }
1589 else
1590 rc = VERR_SHCLPB_EVENT_ID_NOT_FOUND;
1591 }
1592 }
1593 break;
1594 }
1595
1596 case VBOX_SHCL_GUEST_FN_OBJ_OPEN:
1597 {
1598 ASSERT_GUEST_STMT_BREAK(cParms == VBOX_SHCL_CPARMS_OBJ_OPEN, VERR_WRONG_PARAMETER_COUNT);
1599
1600 SHCLOBJOPENCREATEPARMS openCreateParms;
1601 RT_ZERO(openCreateParms);
1602
1603 /* aParms[1] will return the object handle on success; see below. */
1604 rc = HGCMSvcGetStr(&aParms[2], &openCreateParms.pszPath, &openCreateParms.cbPath);
1605 if (RT_SUCCESS(rc))
1606 rc = HGCMSvcGetU32(&aParms[3], &openCreateParms.fCreate);
1607
1608 if (RT_SUCCESS(rc))
1609 {
1610 SHCLOBJHANDLE hObj;
1611 rc = ShClTransferObjOpen(pTransfer, &openCreateParms, &hObj);
1612 if (RT_SUCCESS(rc))
1613 {
1614 LogFlowFunc(("hObj=%RU64\n", hObj));
1615
1616 HGCMSvcSetU64(&aParms[1], hObj);
1617 }
1618 }
1619 break;
1620 }
1621
1622 case VBOX_SHCL_GUEST_FN_OBJ_CLOSE:
1623 {
1624 if (cParms != VBOX_SHCL_CPARMS_OBJ_CLOSE)
1625 break;
1626
1627 SHCLOBJHANDLE hObj;
1628 rc = HGCMSvcGetU64(&aParms[1], &hObj); /* Get object handle. */
1629 if (RT_SUCCESS(rc))
1630 rc = ShClTransferObjClose(pTransfer, hObj);
1631 break;
1632 }
1633
1634 case VBOX_SHCL_GUEST_FN_OBJ_READ:
1635 {
1636 if (cParms != VBOX_SHCL_CPARMS_OBJ_READ)
1637 break;
1638
1639 SHCLOBJHANDLE hObj;
1640 rc = HGCMSvcGetU64(&aParms[1], &hObj); /* Get object handle. */
1641
1642 uint32_t cbToRead = 0;
1643 if (RT_SUCCESS(rc))
1644 rc = HGCMSvcGetU32(&aParms[2], &cbToRead);
1645
1646 void *pvBuf = NULL;
1647 uint32_t cbBuf = 0;
1648 if (RT_SUCCESS(rc))
1649 rc = HGCMSvcGetPv(&aParms[3], &pvBuf, &cbBuf);
1650
1651 LogFlowFunc(("hObj=%RU64, cbBuf=%RU32, cbToRead=%RU32, rc=%Rrc\n", hObj, cbBuf, cbToRead, rc));
1652
1653 if ( RT_SUCCESS(rc)
1654 && ( !cbBuf
1655 || !cbToRead
1656 || cbBuf < cbToRead
1657 )
1658 )
1659 {
1660 rc = VERR_INVALID_PARAMETER;
1661 }
1662
1663 if (RT_SUCCESS(rc))
1664 {
1665 uint32_t cbRead;
1666 rc = ShClTransferObjRead(pTransfer, hObj, pvBuf, cbToRead, 0 /* fFlags */, &cbRead);
1667 if (RT_SUCCESS(rc))
1668 {
1669 HGCMSvcSetU32(&aParms[3], cbRead);
1670
1671 /** @todo Implement checksum support. */
1672 }
1673 }
1674 break;
1675 }
1676
1677 case VBOX_SHCL_GUEST_FN_OBJ_WRITE:
1678 {
1679 SHCLOBJDATACHUNK dataChunk;
1680 rc = shClSvcTransferGetObjDataChunk(cParms, aParms, &dataChunk);
1681 if (RT_SUCCESS(rc))
1682 {
1683 void *pvData = ShClTransferObjDataChunkDup(&dataChunk);
1684 uint32_t cbData = sizeof(SHCLOBJDATACHUNK);
1685
1686 const PSHCLEVENT pEvent = ShClEventSourceGetFromId(&pClient->EventSrc, VBOX_SHCL_CONTEXTID_GET_EVENT(uCID));
1687 if (pEvent)
1688 {
1689 PSHCLEVENTPAYLOAD pPayload;
1690 rc = ShClPayloadAlloc(pEvent->idEvent, pvData, cbData, &pPayload);
1691 if (RT_SUCCESS(rc))
1692 {
1693 rc = ShClEventSignal(pEvent, pPayload);
1694 if (RT_FAILURE(rc))
1695 ShClPayloadFree(pPayload);
1696 }
1697 }
1698 else
1699 rc = VERR_SHCLPB_EVENT_ID_NOT_FOUND;
1700 }
1701
1702 break;
1703 }
1704
1705 default:
1706 rc = VERR_NOT_IMPLEMENTED;
1707 break;
1708 }
1709
1710 LogFlowFunc(("[Client %RU32] Returning rc=%Rrc\n", pClient->State.uClientID, rc));
1711 return rc;
1712}
1713
1714/**
1715 * Transfer host handler for the Shared Clipboard host service.
1716 *
1717 * @returns VBox status code.
1718 * @param u32Function Function number being called.
1719 * @param cParms Number of function parameters supplied.
1720 * @param aParms Array function parameters supplied.
1721 */
1722int shClSvcTransferHostHandler(uint32_t u32Function,
1723 uint32_t cParms,
1724 VBOXHGCMSVCPARM aParms[])
1725{
1726 RT_NOREF(cParms, aParms);
1727
1728 int rc = VERR_NOT_IMPLEMENTED; /* Play safe. */
1729
1730 switch (u32Function)
1731 {
1732 case VBOX_SHCL_HOST_FN_CANCEL: /** @todo Implement this. */
1733 break;
1734
1735 case VBOX_SHCL_HOST_FN_ERROR: /** @todo Implement this. */
1736 break;
1737
1738 default:
1739 break;
1740
1741 }
1742
1743 LogFlowFuncLeaveRC(rc);
1744 return rc;
1745}
1746
1747int shClSvcTransferHostMsgHandler(PSHCLCLIENT pClient, PSHCLCLIENTMSG pMsg)
1748{
1749 RT_NOREF(pClient);
1750
1751 int rc;
1752
1753 switch (pMsg->idMsg)
1754 {
1755 default:
1756 rc = VINF_SUCCESS;
1757 break;
1758 }
1759
1760 LogFlowFuncLeaveRC(rc);
1761 return rc;
1762}
1763
1764/**
1765 * Reports a transfer status to the guest.
1766 *
1767 * @returns VBox status code.
1768 * @param pClient Client that owns the transfer.
1769 * @param pTransfer Transfer to report status for.
1770 * @param uStatus Status to report.
1771 * @param rcTransfer Result code to report. Optional and depending on status.
1772 * @param ppEvent Where to return the wait event on success. Optional.
1773 * Must be released by the caller with ShClEventRelease().
1774 */
1775int shClSvcTransferSendStatus(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, SHCLTRANSFERSTATUS uStatus,
1776 int rcTransfer, PSHCLEVENT *ppEvent)
1777{
1778 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
1779 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1780 /* ppEvent is optional. */
1781
1782 PSHCLCLIENTMSG pMsgReadData = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_STATUS,
1783 VBOX_SHCL_CPARMS_TRANSFER_STATUS);
1784 if (!pMsgReadData)
1785 return VERR_NO_MEMORY;
1786
1787 PSHCLEVENT pEvent;
1788 int rc = ShClEventSourceGenerateAndRegisterEvent(&pClient->EventSrc, &pEvent);
1789 if (RT_SUCCESS(rc))
1790 {
1791 HGCMSvcSetU64(&pMsgReadData->aParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
1792 pTransfer->State.uID, pEvent->idEvent));
1793 HGCMSvcSetU32(&pMsgReadData->aParms[1], pTransfer->State.enmDir);
1794 HGCMSvcSetU32(&pMsgReadData->aParms[2], uStatus);
1795 HGCMSvcSetU32(&pMsgReadData->aParms[3], (uint32_t)rcTransfer); /** @todo uint32_t vs. int. */
1796 HGCMSvcSetU32(&pMsgReadData->aParms[4], 0 /* fFlags, unused */);
1797
1798 shClSvcMsgAdd(pClient, pMsgReadData, true /* fAppend */);
1799
1800 rc = shClSvcClientWakeup(pClient);
1801 if (RT_SUCCESS(rc))
1802 {
1803 LogRel2(("Shared Clipboard: Reported status %s (rc=%Rrc) of transfer %RU32 to guest\n",
1804 ShClTransferStatusToStr(uStatus), rcTransfer, pTransfer->State.uID));
1805
1806 if (ppEvent)
1807 {
1808 *ppEvent = pEvent; /* Takes ownership. */
1809 }
1810 else /* If event is not consumed by the caller, release the event again. */
1811 ShClEventRelease(pEvent);
1812 }
1813 else
1814 ShClEventRelease(pEvent);
1815 }
1816 else
1817 rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
1818
1819 LogFlowFuncLeaveRC(rc);
1820 return rc;
1821}
1822
1823/**
1824 * Starts a new transfer, waiting for acknowledgement by the guest side.
1825 *
1826 * @note Assumes that the client's critical section is taken.
1827 *
1828 * @returns VBox status code.
1829 * @param pClient Client that owns the transfer.
1830 * @param enmDir Transfer direction to start.
1831 * @param enmSource Transfer source to start.
1832 * @param ppTransfer Where to return the created transfer on success. Optional.
1833 */
1834int shClSvcTransferStart(PSHCLCLIENT pClient,
1835 SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource,
1836 PSHCLTRANSFER *ppTransfer)
1837{
1838 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
1839 /* ppTransfer is optional. */
1840
1841 LogFlowFuncEnter();
1842
1843 PSHCLTRANSFERCTX pTxCtx = &pClient->Transfers.Ctx;
1844
1845 ShClTransferCtxCleanup(pTxCtx);
1846
1847 int rc;
1848
1849 if (!ShClTransferCtxTransfersMaximumReached(pTxCtx))
1850 {
1851 LogRel2(("Shared Clipboard: Starting %s transfer ...\n", enmDir == SHCLTRANSFERDIR_FROM_REMOTE ? "read" : "write"));
1852
1853 PSHCLTRANSFER pTransfer;
1854 rc = ShClTransferCreate(&pTransfer);
1855 if (RT_SUCCESS(rc))
1856 {
1857 SHCLTXPROVIDERCREATIONCTX creationCtx;
1858 RT_ZERO(creationCtx);
1859
1860 if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE)
1861 {
1862 creationCtx.Interface.pfnRootsGet = shClSvcTransferIfaceGetRoots;
1863
1864 creationCtx.Interface.pfnListOpen = shClSvcTransferIfaceListOpen;
1865 creationCtx.Interface.pfnListClose = shClSvcTransferIfaceListClose;
1866 creationCtx.Interface.pfnListHdrRead = shClSvcTransferIfaceListHdrRead;
1867 creationCtx.Interface.pfnListEntryRead = shClSvcTransferIfaceListEntryRead;
1868
1869 creationCtx.Interface.pfnObjOpen = shClSvcTransferIfaceObjOpen;
1870 creationCtx.Interface.pfnObjClose = shClSvcTransferIfaceObjClose;
1871 creationCtx.Interface.pfnObjRead = shClSvcTransferIfaceObjRead;
1872 }
1873 else if (enmDir == SHCLTRANSFERDIR_TO_REMOTE)
1874 {
1875 creationCtx.Interface.pfnListHdrWrite = shClSvcTransferIfaceListHdrWrite;
1876 creationCtx.Interface.pfnListEntryWrite = shClSvcTransferIfaceListEntryWrite;
1877 creationCtx.Interface.pfnObjWrite = shClSvcTransferIfaceObjWrite;
1878 }
1879 else
1880 AssertFailed();
1881
1882 creationCtx.enmSource = pClient->State.enmSource;
1883 creationCtx.pvUser = pClient;
1884
1885 rc = ShClTransferSetProviderIface(pTransfer, &creationCtx);
1886 if (RT_SUCCESS(rc))
1887 {
1888 rc = ShClTransferInit(pTransfer, enmDir, enmSource);
1889 if (RT_SUCCESS(rc))
1890 {
1891 SHCLTRANSFERID uTransferID = 0;
1892 rc = ShClTransferCtxTransferRegister(pTxCtx, pTransfer, &uTransferID);
1893 if (RT_SUCCESS(rc))
1894 {
1895 rc = ShClBackendTransferCreate(pClient->pBackend, pClient, pTransfer);
1896 if (RT_SUCCESS(rc))
1897 {
1898 if (RT_SUCCESS(rc))
1899 rc = ShClTransferStart(pTransfer);
1900
1901 if (RT_SUCCESS(rc))
1902 {
1903 PSHCLEVENT pEvent;
1904 rc = shClSvcTransferSendStatus(pClient, pTransfer,
1905 SHCLTRANSFERSTATUS_INITIALIZED, VINF_SUCCESS, &pEvent);
1906 if (RT_SUCCESS(rc))
1907 {
1908 LogRel2(("Shared Clipboard: Waiting for start of transfer %RU32 on guest ...\n",
1909 pTransfer->State.uID));
1910
1911 /* Leave the client's critical section before waiting. */
1912 RTCritSectLeave(&pClient->CritSect);
1913
1914 PSHCLEVENTPAYLOAD pPayload = NULL;
1915 rc = ShClEventWait(pEvent, pTransfer->uTimeoutMs, &pPayload);
1916 if (RT_SUCCESS(rc))
1917 {
1918 Assert(pPayload->cbData == sizeof(SHCLREPLY));
1919 PSHCLREPLY pReply = (PSHCLREPLY)pPayload->pvData;
1920 AssertPtr(pReply);
1921
1922 Assert(pReply->uType == VBOX_SHCL_REPLYMSGTYPE_TRANSFER_STATUS);
1923
1924 if (pReply->u.TransferStatus.uStatus == SHCLTRANSFERSTATUS_STARTED)
1925 {
1926 LogRel2(("Shared Clipboard: Started transfer %RU32 on guest\n", pTransfer->State.uID));
1927 }
1928 else
1929 LogRel(("Shared Clipboard: Guest reported status %s (error %Rrc) while starting transfer %RU32\n",
1930 ShClTransferStatusToStr(pReply->u.TransferStatus.uStatus),
1931 pReply->rc, pTransfer->State.uID));
1932
1933 rc = pReply->rc; /* Set guest rc. */
1934 }
1935 else
1936 LogRel(("Shared Clipboard: Unable to start transfer %RU32 on guest, rc=%Rrc\n",
1937 pTransfer->State.uID, rc));
1938
1939 ShClPayloadFree(pPayload);
1940 ShClEventRelease(pEvent);
1941
1942 /* Re-enter the client's critical section again. */
1943 RTCritSectEnter(&pClient->CritSect);
1944 }
1945 }
1946 }
1947 }
1948
1949 if (RT_FAILURE(rc))
1950 ShClTransferCtxTransferUnregister(pTxCtx, uTransferID);
1951 }
1952 }
1953
1954 if (RT_FAILURE(rc))
1955 {
1956 ShClBackendTransferDestroy(pClient->pBackend, pClient, pTransfer);
1957 ShClTransferDestroy(pTransfer);
1958
1959 RTMemFree(pTransfer);
1960 pTransfer = NULL;
1961 }
1962 else
1963 {
1964 if (ppTransfer)
1965 *ppTransfer = pTransfer;
1966 }
1967 }
1968
1969 if (RT_FAILURE(rc))
1970 LogRel(("Shared Clipboard: Starting transfer failed with %Rrc\n", rc));
1971 }
1972 else
1973 rc = VERR_SHCLPB_MAX_TRANSFERS_REACHED;
1974
1975 LogFlowFuncLeaveRC(rc);
1976 return rc;
1977}
1978
1979/**
1980 * Stops (and destroys) a transfer, communicating the status to the guest side.
1981 *
1982 * @returns VBox status code.
1983 * @param pClient Client that owns the transfer.
1984 * @param pTransfer Transfer to stop.
1985 */
1986int shClSvcTransferStop(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
1987{
1988 PSHCLEVENT pEvent;
1989 int rc = shClSvcTransferSendStatus(pClient, pTransfer,
1990 SHCLTRANSFERSTATUS_STOPPED, VINF_SUCCESS, &pEvent);
1991 if (RT_SUCCESS(rc))
1992 {
1993 LogRel2(("Shared Clipboard: Waiting for stop of transfer %RU32 on guest ...\n", pTransfer->State.uID));
1994
1995 rc = ShClEventWait(pEvent, pTransfer->uTimeoutMs, NULL /* ppPayload */);
1996 if (RT_SUCCESS(rc))
1997 LogRel2(("Shared Clipboard: Stopped transfer %RU32 on guest\n", pTransfer->State.uID));
1998
1999 ShClEventRelease(pEvent);
2000 }
2001
2002 if (RT_FAILURE(rc))
2003 LogRel(("Shared Clipboard: Unable to stop transfer %RU32 on guest, rc=%Rrc\n",
2004 pTransfer->State.uID, rc));
2005
2006 /* Regardless of whether the guest was able to report back and/or stop the transfer, remove the transfer on the host
2007 * so that we don't risk of having stale transfers here. */
2008 int rc2 = ShClTransferCtxTransferUnregister(&pClient->Transfers.Ctx, ShClTransferGetID(pTransfer));
2009 if (RT_SUCCESS(rc2))
2010 {
2011 ShClBackendTransferDestroy(pClient->pBackend, pClient, pTransfer);
2012 ShClTransferDestroy(pTransfer);
2013 pTransfer = NULL;
2014 }
2015
2016 LogFlowFuncLeaveRC(rc);
2017 return rc;
2018}
2019
2020/**
2021 * Sets the host service's (file) transfer mode.
2022 *
2023 * @returns VBox status code.
2024 * @param fMode Transfer mode to set.
2025 */
2026int shClSvcTransferModeSet(uint32_t fMode)
2027{
2028 if (fMode & ~VBOX_SHCL_TRANSFER_MODE_VALID_MASK)
2029 return VERR_INVALID_FLAGS;
2030
2031 g_fTransferMode = fMode;
2032
2033#ifdef DEBUG_andy
2034g_fTransferMode = VBOX_SHCL_TRANSFER_MODE_ENABLED;
2035#endif
2036
2037 LogRel2(("Shared Clipboard: File transfers are now %s\n",
2038 g_fTransferMode != VBOX_SHCL_TRANSFER_MODE_DISABLED ? "enabled" : "disabled"));
2039
2040 /* If file transfers are being disabled, make sure to also reset (destroy) all pending transfers. */
2041 if (g_fTransferMode == VBOX_SHCL_TRANSFER_MODE_DISABLED)
2042 {
2043 ClipboardClientMap::const_iterator itClient = g_mapClients.begin();
2044 while (itClient != g_mapClients.end())
2045 {
2046 PSHCLCLIENT pClient = itClient->second;
2047 AssertPtr(pClient);
2048
2049 shClSvcClientTransfersReset(pClient);
2050
2051 ++itClient;
2052 }
2053 }
2054
2055 LogFlowFuncLeaveRC(VINF_SUCCESS);
2056 return VINF_SUCCESS;
2057}
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