VirtualBox

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

Last change on this file since 87658 was 87658, checked in by vboxsync, 4 years ago

Shared Clipboard/Transfers: Rearranged parameter lists of ShClTransferObj[Read|Write](). ​bugref:9437

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