VirtualBox

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

Last change on this file since 81286 was 81286, checked in by vboxsync, 5 years ago

Shared Clipboard/Transfers: Added IMachine::clipboardFileTransfersEnabled attribute (getter/setter) for enabling/disabling the feature. Disabled by default.

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