VirtualBox

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

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

Shared Clipboard/tstClipboardServiceHost: Added initial tests for setting host transfer mode.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 76.3 KB
Line 
1/* $Id: VBoxSharedClipboardSvc-transfers.cpp 81449 2019-10-22 13:03:29Z 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 HGCMSvcSetU64(&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 HGCMSvcSetU64(&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 HGCMSvcSetU64(&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 HGCMSvcSetU64(&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 HGCMSvcSetU64(&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 HGCMSvcSetU64(&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 HGCMSvcSetU64(&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 HGCMSvcSetU64(&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_REPORT_FEATURES:
746 RT_FALL_THROUGH();
747 case VBOX_SHCL_GUEST_FN_QUERY_FEATURES:
748 RT_FALL_THROUGH();
749 case VBOX_SHCL_GUEST_FN_MSG_GET:
750 RT_FALL_THROUGH();
751 case VBOX_SHCL_GUEST_FN_REPLY:
752 RT_FALL_THROUGH();
753 case VBOX_SHCL_GUEST_FN_CANCEL:
754 RT_FALL_THROUGH();
755 case VBOX_SHCL_GUEST_FN_ERROR:
756 RT_FALL_THROUGH();
757 case VBOX_SHCL_GUEST_FN_LIST_OPEN:
758 RT_FALL_THROUGH();
759 case VBOX_SHCL_GUEST_FN_LIST_CLOSE:
760 RT_FALL_THROUGH();
761 case VBOX_SHCL_GUEST_FN_OBJ_OPEN:
762 RT_FALL_THROUGH();
763 case VBOX_SHCL_GUEST_FN_OBJ_CLOSE:
764 fAllowed = fHostToGuest || fGuestToHost;
765 break;
766
767 default:
768 break;
769 }
770
771 LogFlowFunc(("uMsg=%RU32 (%s), uMode=%RU32 -> fAllowed=%RTbool\n", uMsg, ShClGuestMsgToStr(uMsg), uMode, fAllowed));
772 return fAllowed;
773}
774
775/**
776 * Gets a transfer message reply from HGCM service parameters.
777 *
778 * @returns VBox status code.
779 * @param cParms Number of HGCM parameters supplied in \a paParms.
780 * @param paParms Array of HGCM parameters.
781 * @param pReply Where to store the reply.
782 */
783static int shclSvcTransferGetReply(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
784 PSHCLREPLY pReply)
785{
786 int rc;
787
788 if (cParms >= VBOX_SHCL_CPARMS_REPLY_MIN)
789 {
790 uint32_t cbPayload = 0;
791
792 /* paParms[0] has the context ID. */
793 rc = HGCMSvcGetU32(&paParms[1], &pReply->uType);
794 if (RT_SUCCESS(rc))
795 rc = HGCMSvcGetU32(&paParms[2], &pReply->rc);
796 if (RT_SUCCESS(rc))
797 rc = HGCMSvcGetU32(&paParms[3], &cbPayload);
798 if (RT_SUCCESS(rc))
799 {
800 rc = HGCMSvcGetPv(&paParms[4], &pReply->pvPayload, &pReply->cbPayload);
801 AssertReturn(cbPayload == pReply->cbPayload, VERR_INVALID_PARAMETER);
802 }
803
804 if (RT_SUCCESS(rc))
805 {
806 rc = VERR_INVALID_PARAMETER; /* Play safe. */
807
808 switch (pReply->uType)
809 {
810 case VBOX_SHCL_REPLYMSGTYPE_TRANSFER_STATUS:
811 {
812 if (cParms >= 6)
813 rc = HGCMSvcGetU32(&paParms[5], &pReply->u.TransferStatus.uStatus);
814
815 LogFlowFunc(("uTransferStatus=%RU32\n", pReply->u.TransferStatus.uStatus));
816 break;
817 }
818
819 case VBOX_SHCL_REPLYMSGTYPE_LIST_OPEN:
820 {
821 if (cParms >= 6)
822 rc = HGCMSvcGetU64(&paParms[5], &pReply->u.ListOpen.uHandle);
823
824 LogFlowFunc(("hListOpen=%RU64\n", pReply->u.ListOpen.uHandle));
825 break;
826 }
827
828 case VBOX_SHCL_REPLYMSGTYPE_LIST_CLOSE:
829 {
830 if (cParms >= 6)
831 rc = HGCMSvcGetU64(&paParms[5], &pReply->u.ListClose.uHandle);
832
833 LogFlowFunc(("hListClose=%RU64\n", pReply->u.ListClose.uHandle));
834 break;
835 }
836
837 case VBOX_SHCL_REPLYMSGTYPE_OBJ_OPEN:
838 {
839 if (cParms >= 6)
840 rc = HGCMSvcGetU64(&paParms[5], &pReply->u.ObjOpen.uHandle);
841
842 LogFlowFunc(("hObjOpen=%RU64\n", pReply->u.ObjOpen.uHandle));
843 break;
844 }
845
846 case VBOX_SHCL_REPLYMSGTYPE_OBJ_CLOSE:
847 {
848 if (cParms >= 6)
849 rc = HGCMSvcGetU64(&paParms[5], &pReply->u.ObjClose.uHandle);
850
851 LogFlowFunc(("hObjClose=%RU64\n", pReply->u.ObjClose.uHandle));
852 break;
853 }
854
855 default:
856 rc = VERR_NOT_SUPPORTED;
857 break;
858 }
859 }
860 }
861 else
862 rc = VERR_INVALID_PARAMETER;
863
864 LogFlowFuncLeaveRC(rc);
865 return rc;
866}
867
868/**
869 * Gets a transfer root list header from HGCM service parameters.
870 *
871 * @returns VBox status code.
872 * @param cParms Number of HGCM parameters supplied in \a paParms.
873 * @param paParms Array of HGCM parameters.
874 * @param pRootLstHdr Where to store the transfer root list header on success.
875 */
876static int shclSvcTransferGetRootListHdr(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
877 PSHCLROOTLISTHDR pRootLstHdr)
878{
879 int rc;
880
881 if (cParms == VBOX_SHCL_CPARMS_ROOT_LIST_HDR_WRITE)
882 {
883 rc = HGCMSvcGetU32(&paParms[1], &pRootLstHdr->fRoots);
884 if (RT_SUCCESS(rc))
885 rc = HGCMSvcGetU32(&paParms[2], &pRootLstHdr->cRoots);
886 }
887 else
888 rc = VERR_INVALID_PARAMETER;
889
890 LogFlowFuncLeaveRC(rc);
891 return rc;
892}
893
894/**
895 * Gets a transfer root list entry from HGCM service parameters.
896 *
897 * @returns VBox status code.
898 * @param cParms Number of HGCM parameters supplied in \a paParms.
899 * @param paParms Array of HGCM parameters.
900 * @param pListEntry Where to store the root list entry.
901 */
902static int shclSvcTransferGetRootListEntry(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
903 PSHCLROOTLISTENTRY pListEntry)
904{
905 int rc;
906
907 if (cParms == VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_WRITE)
908 {
909 rc = HGCMSvcGetU32(&paParms[1], &pListEntry->fInfo);
910 /* Note: paParms[2] contains the entry index, currently being ignored. */
911 if (RT_SUCCESS(rc))
912 rc = HGCMSvcGetPv(&paParms[3], (void **)&pListEntry->pszName, &pListEntry->cbName);
913 if (RT_SUCCESS(rc))
914 {
915 uint32_t cbInfo;
916 rc = HGCMSvcGetU32(&paParms[4], &cbInfo);
917 if (RT_SUCCESS(rc))
918 {
919 rc = HGCMSvcGetPv(&paParms[5], &pListEntry->pvInfo, &pListEntry->cbInfo);
920 AssertReturn(cbInfo == pListEntry->cbInfo, VERR_INVALID_PARAMETER);
921 }
922 }
923 }
924 else
925 rc = VERR_INVALID_PARAMETER;
926
927 LogFlowFuncLeaveRC(rc);
928 return rc;
929}
930
931/**
932 * Gets a transfer list open request from HGCM service parameters.
933 *
934 * @returns VBox status code.
935 * @param cParms Number of HGCM parameters supplied in \a paParms.
936 * @param paParms Array of HGCM parameters.
937 * @param pOpenParms Where to store the open parameters of the request.
938 */
939static int shclSvcTransferGetListOpen(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
940 PSHCLLISTOPENPARMS pOpenParms)
941{
942 int rc;
943
944 if (cParms == VBOX_SHCL_CPARMS_LIST_OPEN)
945 {
946 uint32_t cbPath = 0;
947 uint32_t cbFilter = 0;
948
949 rc = HGCMSvcGetU32(&paParms[1], &pOpenParms->fList);
950 if (RT_SUCCESS(rc))
951 rc = HGCMSvcGetU32(&paParms[2], &cbFilter);
952 if (RT_SUCCESS(rc))
953 {
954 rc = HGCMSvcGetStr(&paParms[3], &pOpenParms->pszFilter, &pOpenParms->cbFilter);
955 AssertReturn(cbFilter == pOpenParms->cbFilter, VERR_INVALID_PARAMETER);
956 }
957 if (RT_SUCCESS(rc))
958 rc = HGCMSvcGetU32(&paParms[4], &cbPath);
959 if (RT_SUCCESS(rc))
960 {
961 rc = HGCMSvcGetStr(&paParms[5], &pOpenParms->pszPath, &pOpenParms->cbPath);
962 AssertReturn(cbPath == pOpenParms->cbPath, VERR_INVALID_PARAMETER);
963 }
964
965 /** @todo Some more validation. */
966 }
967 else
968 rc = VERR_INVALID_PARAMETER;
969
970 LogFlowFuncLeaveRC(rc);
971 return rc;
972}
973
974/**
975 * Sets a transfer list open request to HGCM service parameters.
976 *
977 * @returns VBox status code.
978 * @param cParms Number of HGCM parameters supplied in \a paParms.
979 * @param paParms Array of HGCM parameters.
980 * @param pMsgCtx Message context to use.
981 * @param pOpenParms List open parameters to set.
982 */
983static int shclSvcTransferSetListOpen(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
984 PSHCLMSGCTX pMsgCtx, PSHCLLISTOPENPARMS pOpenParms)
985{
986 int rc;
987
988 if (cParms == VBOX_SHCL_CPARMS_LIST_OPEN)
989 {
990 HGCMSvcSetU64(&paParms[0], pMsgCtx->uContextID);
991 HGCMSvcSetU32(&paParms[1], pOpenParms->fList);
992 HGCMSvcSetU32(&paParms[2], pOpenParms->cbFilter);
993 HGCMSvcSetPv (&paParms[3], pOpenParms->pszFilter, pOpenParms->cbFilter);
994 HGCMSvcSetU32(&paParms[4], pOpenParms->cbPath);
995 HGCMSvcSetPv (&paParms[5], pOpenParms->pszPath, pOpenParms->cbPath);
996 HGCMSvcSetU64(&paParms[6], 0); /* OUT: uHandle */
997
998 rc = VINF_SUCCESS;
999 }
1000 else
1001 rc = VERR_INVALID_PARAMETER;
1002
1003 LogFlowFuncLeaveRC(rc);
1004 return rc;
1005}
1006
1007/**
1008 * Sets a transfer list close request to HGCM service parameters.
1009 *
1010 * @returns VBox status code.
1011 * @param cParms Number of HGCM parameters supplied in \a paParms.
1012 * @param paParms Array of HGCM parameters.
1013 * @param pMsgCtx Message context to use.
1014 * @param hList Handle of list to close.
1015 */
1016static int shclSvcTransferSetListClose(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
1017 PSHCLMSGCTX pMsgCtx, SHCLLISTHANDLE hList)
1018{
1019 int rc;
1020
1021 if (cParms == VBOX_SHCL_CPARMS_LIST_CLOSE)
1022 {
1023 HGCMSvcSetU64(&paParms[0], pMsgCtx->uContextID);
1024 HGCMSvcSetU64(&paParms[1], hList);
1025
1026 rc = VINF_SUCCESS;
1027 }
1028 else
1029 rc = VERR_INVALID_PARAMETER;
1030
1031 LogFlowFuncLeaveRC(rc);
1032 return rc;
1033}
1034
1035/**
1036 * Gets a transfer list header from HGCM service parameters.
1037 *
1038 * @returns VBox status code.
1039 * @param cParms Number of HGCM parameters supplied in \a paParms.
1040 * @param paParms Array of HGCM parameters.
1041 * @param phList Where to store the list handle.
1042 * @param pListHdr Where to store the list header.
1043 */
1044static int shclSvcTransferGetListHdr(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
1045 PSHCLLISTHANDLE phList, PSHCLLISTHDR pListHdr)
1046{
1047 int rc;
1048
1049 if (cParms == VBOX_SHCL_CPARMS_LIST_HDR)
1050 {
1051 rc = HGCMSvcGetU64(&paParms[1], phList);
1052 /* Note: Flags (paParms[2]) not used here. */
1053 if (RT_SUCCESS(rc))
1054 rc = HGCMSvcGetU32(&paParms[3], &pListHdr->fFeatures);
1055 if (RT_SUCCESS(rc))
1056 rc = HGCMSvcGetU64(&paParms[4], &pListHdr->cTotalObjects);
1057 if (RT_SUCCESS(rc))
1058 rc = HGCMSvcGetU64(&paParms[5], &pListHdr->cbTotalSize);
1059
1060 if (RT_SUCCESS(rc))
1061 {
1062 /** @todo Validate pvMetaFmt + cbMetaFmt. */
1063 /** @todo Validate header checksum. */
1064 }
1065 }
1066 else
1067 rc = VERR_INVALID_PARAMETER;
1068
1069 LogFlowFuncLeaveRC(rc);
1070 return rc;
1071}
1072
1073#if 0
1074/**
1075 * Sets a transfer list header to HGCM service parameters.
1076 *
1077 * @returns VBox status code.
1078 * @param cParms Number of HGCM parameters supplied in \a paParms.
1079 * @param paParms Array of HGCM parameters.
1080 * @param pMsgCtx Message context to use.
1081 * @param pListHdr Pointer to data to set to the HGCM parameters.
1082 */
1083static int shclSvcTransferSetListHdr(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
1084 PVBOXSHCLMSGCTX pMsgCtx, PSHCLLISTHDR pListHdr)
1085{
1086 int rc;
1087
1088 if (cParms == VBOX_SHCL_CPARMS_LIST_HDR)
1089 {
1090 /** @todo Set pvMetaFmt + cbMetaFmt. */
1091 /** @todo Calculate header checksum. */
1092
1093 HGCMSvcSetU64(&paParms[0], pMsgCtx->uContextID);
1094 HGCMSvcSetU32(&paParms[1], pListHdr->fFeatures);
1095 HGCMSvcSetU32(&paParms[2], 0 /* Features, will be returned on success */);
1096 HGCMSvcSetU64(&paParms[3], pListHdr->cTotalObjects);
1097 HGCMSvcSetU64(&paParms[4], pListHdr->cbTotalSize);
1098
1099 rc = VINF_SUCCESS;
1100 }
1101 else
1102 rc = VERR_INVALID_PARAMETER;
1103
1104 LogFlowFuncLeaveRC(rc);
1105 return rc;
1106}
1107#endif
1108
1109/**
1110 * Gets a transfer list entry from HGCM service parameters.
1111 *
1112 * @returns VBox status code.
1113 * @param cParms Number of HGCM parameters supplied in \a paParms.
1114 * @param paParms Array of HGCM parameters.
1115 * @param phList Where to store the list handle.
1116 * @param pListEntry Where to store the list entry.
1117 */
1118static int shclSvcTransferGetListEntry(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
1119 PSHCLLISTHANDLE phList, PSHCLLISTENTRY pListEntry)
1120{
1121 int rc;
1122
1123 if (cParms == VBOX_SHCL_CPARMS_LIST_ENTRY)
1124 {
1125 rc = HGCMSvcGetU64(&paParms[1], phList);
1126 if (RT_SUCCESS(rc))
1127 rc = HGCMSvcGetU32(&paParms[2], &pListEntry->fInfo);
1128 if (RT_SUCCESS(rc))
1129 rc = HGCMSvcGetPv(&paParms[3], (void **)&pListEntry->pszName, &pListEntry->cbName);
1130 if (RT_SUCCESS(rc))
1131 {
1132 uint32_t cbInfo;
1133 rc = HGCMSvcGetU32(&paParms[4], &cbInfo);
1134 if (RT_SUCCESS(rc))
1135 {
1136 rc = HGCMSvcGetPv(&paParms[5], &pListEntry->pvInfo, &pListEntry->cbInfo);
1137 AssertReturn(cbInfo == pListEntry->cbInfo, VERR_INVALID_PARAMETER);
1138 }
1139 }
1140
1141 if (RT_SUCCESS(rc))
1142 {
1143 if (!ShClTransferListEntryIsValid(pListEntry))
1144 rc = VERR_INVALID_PARAMETER;
1145 }
1146 }
1147 else
1148 rc = VERR_INVALID_PARAMETER;
1149
1150 LogFlowFuncLeaveRC(rc);
1151 return rc;
1152}
1153
1154#if 0
1155/**
1156 * Sets a transfer data chunk to HGCM service parameters.
1157 *
1158 * @returns VBox status code.
1159 * @param cParms Number of HGCM parameters supplied in \a paParms.
1160 * @param paParms Array of HGCM parameters.
1161 * @param pMsgCtx Message context to use.
1162 * @param pListEntry Pointer to data to set to the HGCM parameters.
1163 */
1164static int shclSvcTransferSetListEntry(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
1165 PVBOXSHCLMSGCTX pMsgCtx, PSHCLLISTENTRY pListEntry)
1166{
1167 int rc;
1168
1169 if (cParms == VBOX_SHCL_CPARMS_LIST_ENTRY)
1170 {
1171 /** @todo Calculate chunk checksum. */
1172
1173 HGCMSvcSetU64(&paParms[0], pMsgCtx->uContextID);
1174 HGCMSvcSetU32(&paParms[1], pListEntry->fInfo);
1175 HGCMSvcSetU32(&paParms[2], pListEntry->cbInfo);
1176 HGCMSvcSetPv (&paParms[3], pListEntry->pvInfo, pListEntry->cbInfo);
1177
1178 rc = VINF_SUCCESS;
1179 }
1180 else
1181 rc = VERR_INVALID_PARAMETER;
1182
1183 LogFlowFuncLeaveRC(rc);
1184 return rc;
1185}
1186#endif
1187
1188/**
1189 * Gets a transfer object data chunk from HGCM service parameters.
1190 *
1191 * @returns VBox status code.
1192 * @param cParms Number of HGCM parameters supplied in \a paParms.
1193 * @param paParms Array of HGCM parameters.
1194 * @param pDataChunk Where to store the object data chunk data.
1195 */
1196static int shclSvcTransferGetObjDataChunk(uint32_t cParms, VBOXHGCMSVCPARM paParms[], PSHCLOBJDATACHUNK pDataChunk)
1197{
1198 AssertPtrReturn(paParms, VERR_INVALID_PARAMETER);
1199 AssertPtrReturn(pDataChunk, VERR_INVALID_PARAMETER);
1200
1201 int rc;
1202
1203 if (cParms == VBOX_SHCL_CPARMS_OBJ_WRITE)
1204 {
1205 rc = HGCMSvcGetU64(&paParms[1], &pDataChunk->uHandle);
1206 if (RT_SUCCESS(rc))
1207 {
1208 uint32_t cbData;
1209 rc = HGCMSvcGetU32(&paParms[2], &cbData);
1210 if (RT_SUCCESS(rc))
1211 {
1212 rc = HGCMSvcGetPv(&paParms[3], &pDataChunk->pvData, &pDataChunk->cbData);
1213 AssertReturn(cbData == pDataChunk->cbData, VERR_INVALID_PARAMETER);
1214
1215 /** @todo Implement checksum handling. */
1216 }
1217 }
1218 }
1219 else
1220 rc = VERR_INVALID_PARAMETER;
1221
1222 LogFlowFuncLeaveRC(rc);
1223 return rc;
1224}
1225
1226/**
1227 * Handles a guest reply (VBOX_SHCL_GUEST_FN_REPLY) message.
1228 *
1229 * @returns VBox status code.
1230 * @param pClient Pointer to associated client.
1231 * @param pTransfer Pointer to transfer to handle guest reply for.
1232 * @param cParms Number of function parameters supplied.
1233 * @param paParms Array function parameters supplied.
1234 */
1235static int shclSvcTransferHandleReply(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer,
1236 uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1237{
1238 RT_NOREF(pClient);
1239
1240 int rc;
1241
1242 uint32_t cbReply = sizeof(SHCLREPLY);
1243 PSHCLREPLY pReply = (PSHCLREPLY)RTMemAlloc(cbReply);
1244 if (pReply)
1245 {
1246 rc = shclSvcTransferGetReply(cParms, paParms, pReply);
1247 if (RT_SUCCESS(rc))
1248 {
1249 PSHCLEVENTPAYLOAD pPayload
1250 = (PSHCLEVENTPAYLOAD)RTMemAlloc(sizeof(SHCLEVENTPAYLOAD));
1251 if (pPayload)
1252 {
1253 pPayload->pvData = pReply;
1254 pPayload->cbData = cbReply;
1255
1256 switch (pReply->uType)
1257 {
1258 case VBOX_SHCL_REPLYMSGTYPE_TRANSFER_STATUS:
1259 RT_FALL_THROUGH();
1260 case VBOX_SHCL_REPLYMSGTYPE_LIST_OPEN:
1261 RT_FALL_THROUGH();
1262 case VBOX_SHCL_REPLYMSGTYPE_LIST_CLOSE:
1263 RT_FALL_THROUGH();
1264 case VBOX_SHCL_REPLYMSGTYPE_OBJ_OPEN:
1265 RT_FALL_THROUGH();
1266 case VBOX_SHCL_REPLYMSGTYPE_OBJ_CLOSE:
1267 {
1268 uint64_t uCID;
1269 rc = HGCMSvcGetU64(&paParms[0], &uCID);
1270 if (RT_SUCCESS(rc))
1271 {
1272 const SHCLEVENTID uEvent = VBOX_SHCL_CONTEXTID_GET_EVENT(uCID);
1273
1274 LogFlowFunc(("uCID=%RU64 -> uEvent=%RU32\n", uCID, uEvent));
1275
1276 rc = ShClEventSignal(&pTransfer->Events, uEvent, pPayload);
1277 }
1278 break;
1279 }
1280
1281 default:
1282 rc = VERR_NOT_FOUND;
1283 break;
1284 }
1285
1286 if (RT_FAILURE(rc))
1287 {
1288 if (pPayload)
1289 RTMemFree(pPayload);
1290 }
1291 }
1292 else
1293 rc = VERR_NO_MEMORY;
1294 }
1295 }
1296 else
1297 rc = VERR_NO_MEMORY;
1298
1299 if (RT_FAILURE(rc))
1300 {
1301 if (pReply)
1302 RTMemFree(pReply);
1303 }
1304
1305 LogFlowFuncLeaveRC(rc);
1306 return rc;
1307}
1308
1309/**
1310 * Transfer client (guest) handler for the Shared Clipboard host service.
1311 *
1312 * @returns VBox status code, or VINF_HGCM_ASYNC_EXECUTE if returning to the client will be deferred.
1313 * @param pClient Pointer to associated client.
1314 * @param callHandle The client's call handle of this call.
1315 * @param u32Function Function number being called.
1316 * @param cParms Number of function parameters supplied.
1317 * @param paParms Array function parameters supplied.
1318 * @param tsArrival Timestamp of arrival.
1319 */
1320int shclSvcTransferHandler(PSHCLCLIENT pClient,
1321 VBOXHGCMCALLHANDLE callHandle,
1322 uint32_t u32Function,
1323 uint32_t cParms,
1324 VBOXHGCMSVCPARM paParms[],
1325 uint64_t tsArrival)
1326{
1327 RT_NOREF(callHandle, paParms, tsArrival);
1328
1329 LogFlowFunc(("uClient=%RU32, u32Function=%RU32 (%s), cParms=%RU32, g_ExtState.pfnExtension=%p\n",
1330 pClient->State.uClientID, u32Function, ShClGuestMsgToStr(u32Function), cParms, g_ExtState.pfnExtension));
1331
1332 /* Check if we've the right mode set. */
1333 if (!shclSvcTransferMsgIsAllowed(shclSvcGetMode(), u32Function))
1334 {
1335 LogFunc(("Wrong clipboard mode, denying access\n"));
1336 return VERR_ACCESS_DENIED;
1337 }
1338
1339 /* A (valid) service extension is needed because VBoxSVC needs to keep track of the
1340 * clipboard areas cached on the host. */
1341 if (!g_ExtState.pfnExtension)
1342 {
1343#ifdef DEBUG_andy
1344 AssertPtr(g_ExtState.pfnExtension);
1345#endif
1346 LogFunc(("Invalid / no service extension set, skipping transfer handling\n"));
1347 return VERR_NOT_SUPPORTED;
1348 }
1349
1350 int rc = VERR_INVALID_PARAMETER; /* Play safe by default. */
1351
1352 /*
1353 * Pre-check: For certain messages we need to make sure that a (right) transfer is present.
1354 */
1355 uint64_t uCID = 0; /* Context ID */
1356 PSHCLTRANSFER pTransfer = NULL;
1357
1358 switch (u32Function)
1359 {
1360 default:
1361 {
1362 if (!ShClTransferCtxGetTotalTransfers(&pClient->TransferCtx))
1363 {
1364 LogFunc(("No transfers found\n"));
1365 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
1366 break;
1367 }
1368
1369 if (cParms < 1)
1370 break;
1371
1372 rc = HGCMSvcGetU64(&paParms[0], &uCID);
1373 if (RT_FAILURE(rc))
1374 break;
1375
1376 const SHCLTRANSFERID uTransferID = VBOX_SHCL_CONTEXTID_GET_TRANSFER(uCID);
1377
1378 pTransfer = ShClTransferCtxGetTransfer(&pClient->TransferCtx, uTransferID);
1379 if (!pTransfer)
1380 {
1381 LogFunc(("Transfer with ID %RU32 not found\n", uTransferID));
1382 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
1383 }
1384 break;
1385 }
1386 }
1387
1388 if (RT_FAILURE(rc))
1389 return rc;
1390
1391 rc = VERR_INVALID_PARAMETER; /* Play safe. */
1392
1393 switch (u32Function)
1394 {
1395 case VBOX_SHCL_GUEST_FN_REPLY:
1396 {
1397 rc = shclSvcTransferHandleReply(pClient, pTransfer, cParms, paParms);
1398 break;
1399 }
1400
1401 case VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_READ:
1402 {
1403 if (cParms != VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ)
1404 break;
1405
1406 SHCLROOTLISTHDR rootListHdr;
1407 RT_ZERO(rootListHdr);
1408
1409 rootListHdr.cRoots = ShClTransferRootsCount(pTransfer);
1410
1411 HGCMSvcSetU64(&paParms[0], 0 /* Context ID */);
1412 HGCMSvcSetU32(&paParms[1], rootListHdr.fRoots);
1413 HGCMSvcSetU32(&paParms[2], rootListHdr.cRoots);
1414
1415 rc = VINF_SUCCESS;
1416 break;
1417 }
1418
1419 case VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_WRITE:
1420 {
1421 SHCLROOTLISTHDR lstHdr;
1422 rc = shclSvcTransferGetRootListHdr(cParms, paParms, &lstHdr);
1423 if (RT_SUCCESS(rc))
1424 {
1425 void *pvData = ShClTransferRootListHdrDup(&lstHdr);
1426 uint32_t cbData = sizeof(SHCLROOTLISTHDR);
1427
1428 const SHCLEVENTID uEvent = VBOX_SHCL_CONTEXTID_GET_EVENT(uCID);
1429
1430 PSHCLEVENTPAYLOAD pPayload;
1431 rc = ShClPayloadAlloc(uEvent, pvData, cbData, &pPayload);
1432 if (RT_SUCCESS(rc))
1433 {
1434 rc = ShClEventSignal(&pTransfer->Events, uEvent, pPayload);
1435 if (RT_FAILURE(rc))
1436 ShClPayloadFree(pPayload);
1437 }
1438 }
1439 break;
1440 }
1441
1442 case VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_READ:
1443 {
1444 if (cParms != VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ)
1445 break;
1446
1447 /* paParms[1] contains fInfo flags, currently unused. */
1448 uint32_t uIndex;
1449 rc = HGCMSvcGetU32(&paParms[2], &uIndex);
1450 if (RT_SUCCESS(rc))
1451 {
1452 SHCLROOTLISTENTRY rootListEntry;
1453 rc = ShClTransferRootsEntry(pTransfer, uIndex, &rootListEntry);
1454 if (RT_SUCCESS(rc))
1455 {
1456 HGCMSvcSetPv (&paParms[3], rootListEntry.pszName, rootListEntry.cbName);
1457 HGCMSvcSetU32(&paParms[4], rootListEntry.cbInfo);
1458 HGCMSvcSetPv (&paParms[5], rootListEntry.pvInfo, rootListEntry.cbInfo);
1459 }
1460 }
1461 break;
1462 }
1463
1464 case VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_WRITE:
1465 {
1466 SHCLROOTLISTENTRY lstEntry;
1467 rc = shclSvcTransferGetRootListEntry(cParms, paParms, &lstEntry);
1468 if (RT_SUCCESS(rc))
1469 {
1470 void *pvData = ShClTransferRootListEntryDup(&lstEntry);
1471 uint32_t cbData = sizeof(SHCLROOTLISTENTRY);
1472
1473 const SHCLEVENTID uEvent = VBOX_SHCL_CONTEXTID_GET_EVENT(uCID);
1474
1475 PSHCLEVENTPAYLOAD pPayload;
1476 rc = ShClPayloadAlloc(uEvent, pvData, cbData, &pPayload);
1477 if (RT_SUCCESS(rc))
1478 {
1479 rc = ShClEventSignal(&pTransfer->Events, uEvent, pPayload);
1480 if (RT_FAILURE(rc))
1481 ShClPayloadFree(pPayload);
1482 }
1483 }
1484 break;
1485 }
1486
1487 case VBOX_SHCL_GUEST_FN_LIST_OPEN:
1488 {
1489 SHCLLISTOPENPARMS listOpenParms;
1490 rc = shclSvcTransferGetListOpen(cParms, paParms, &listOpenParms);
1491 if (RT_SUCCESS(rc))
1492 {
1493 SHCLLISTHANDLE hList;
1494 rc = ShClTransferListOpen(pTransfer, &listOpenParms, &hList);
1495 if (RT_SUCCESS(rc))
1496 {
1497 /* Return list handle. */
1498 HGCMSvcSetU32(&paParms[1], hList);
1499 }
1500 }
1501 break;
1502 }
1503
1504 case VBOX_SHCL_GUEST_FN_LIST_CLOSE:
1505 {
1506 if (cParms != VBOX_SHCL_CPARMS_LIST_CLOSE)
1507 break;
1508
1509 SHCLLISTHANDLE hList;
1510 rc = HGCMSvcGetU64(&paParms[1], &hList);
1511 if (RT_SUCCESS(rc))
1512 {
1513 rc = ShClTransferListClose(pTransfer, hList);
1514 }
1515 break;
1516 }
1517
1518 case VBOX_SHCL_GUEST_FN_LIST_HDR_READ:
1519 {
1520 if (cParms != VBOX_SHCL_CPARMS_LIST_HDR)
1521 break;
1522
1523 SHCLLISTHANDLE hList;
1524 rc = HGCMSvcGetU64(&paParms[1], &hList); /* Get list handle. */
1525 if (RT_SUCCESS(rc))
1526 {
1527 SHCLLISTHDR hdrList;
1528 rc = ShClTransferListGetHeader(pTransfer, hList, &hdrList);
1529 /*if (RT_SUCCESS(rc))
1530 rc = shclSvcTransferSetListHdr(cParms, paParms, &hdrList);*/
1531 }
1532 break;
1533 }
1534
1535 case VBOX_SHCL_GUEST_FN_LIST_HDR_WRITE:
1536 {
1537 SHCLLISTHDR hdrList;
1538 rc = ShClTransferListHdrInit(&hdrList);
1539 if (RT_SUCCESS(rc))
1540 {
1541 SHCLLISTHANDLE hList;
1542 rc = shclSvcTransferGetListHdr(cParms, paParms, &hList, &hdrList);
1543 if (RT_SUCCESS(rc))
1544 {
1545 void *pvData = ShClTransferListHdrDup(&hdrList);
1546 uint32_t cbData = sizeof(SHCLLISTHDR);
1547
1548 const SHCLEVENTID uEvent = VBOX_SHCL_CONTEXTID_GET_EVENT(uCID);
1549
1550 PSHCLEVENTPAYLOAD pPayload;
1551 rc = ShClPayloadAlloc(uEvent, pvData, cbData, &pPayload);
1552 if (RT_SUCCESS(rc))
1553 {
1554 rc = ShClEventSignal(&pTransfer->Events, uEvent, pPayload);
1555 if (RT_FAILURE(rc))
1556 ShClPayloadFree(pPayload);
1557 }
1558 }
1559 }
1560 break;
1561 }
1562
1563 case VBOX_SHCL_GUEST_FN_LIST_ENTRY_READ:
1564 {
1565 if (cParms != VBOX_SHCL_CPARMS_LIST_ENTRY)
1566 break;
1567
1568 SHCLLISTHANDLE hList;
1569 rc = HGCMSvcGetU64(&paParms[1], &hList); /* Get list handle. */
1570 if (RT_SUCCESS(rc))
1571 {
1572 SHCLLISTENTRY entryList;
1573 rc = ShClTransferListRead(pTransfer, hList, &entryList);
1574 }
1575 break;
1576 }
1577
1578 case VBOX_SHCL_GUEST_FN_LIST_ENTRY_WRITE:
1579 {
1580 SHCLLISTENTRY entryList;
1581 rc = ShClTransferListEntryInit(&entryList);
1582 if (RT_SUCCESS(rc))
1583 {
1584 SHCLLISTHANDLE hList;
1585 rc = shclSvcTransferGetListEntry(cParms, paParms, &hList, &entryList);
1586 if (RT_SUCCESS(rc))
1587 {
1588 void *pvData = ShClTransferListEntryDup(&entryList);
1589 uint32_t cbData = sizeof(SHCLLISTENTRY);
1590
1591 const SHCLEVENTID uEvent = VBOX_SHCL_CONTEXTID_GET_EVENT(uCID);
1592
1593 PSHCLEVENTPAYLOAD pPayload;
1594 rc = ShClPayloadAlloc(uEvent, pvData, cbData, &pPayload);
1595 if (RT_SUCCESS(rc))
1596 {
1597 rc = ShClEventSignal(&pTransfer->Events, uEvent, pPayload);
1598 if (RT_FAILURE(rc))
1599 ShClPayloadFree(pPayload);
1600 }
1601 }
1602 }
1603 break;
1604 }
1605
1606 case VBOX_SHCL_GUEST_FN_OBJ_OPEN:
1607 {
1608 if (cParms != VBOX_SHCL_CPARMS_OBJ_OPEN)
1609 break;
1610
1611 SHCLOBJOPENCREATEPARMS openCreateParms;
1612 RT_ZERO(openCreateParms);
1613
1614 uint32_t cbPath;
1615 rc = HGCMSvcGetU32(&paParms[2], &cbPath);
1616 if (RT_SUCCESS(rc))
1617 {
1618 rc = HGCMSvcGetPv(&paParms[3], (void **)&openCreateParms.pszPath, &openCreateParms.cbPath);
1619 if (cbPath != openCreateParms.cbPath)
1620 rc = VERR_INVALID_PARAMETER;
1621 }
1622 if (RT_SUCCESS(rc))
1623 rc = HGCMSvcGetU32(&paParms[4], &openCreateParms.fCreate);
1624
1625 if (RT_SUCCESS(rc))
1626 {
1627 SHCLOBJHANDLE hObj;
1628 rc = ShClTransferObjOpen(pTransfer, &openCreateParms, &hObj);
1629 if (RT_SUCCESS(rc))
1630 {
1631 LogFlowFunc(("hObj=%RU64\n", hObj));
1632
1633 HGCMSvcSetU64(&paParms[1], hObj);
1634 }
1635 }
1636 break;
1637 }
1638
1639 case VBOX_SHCL_GUEST_FN_OBJ_CLOSE:
1640 {
1641 if (cParms != VBOX_SHCL_CPARMS_OBJ_CLOSE)
1642 break;
1643
1644 SHCLOBJHANDLE hObj;
1645 rc = HGCMSvcGetU64(&paParms[1], &hObj); /* Get object handle. */
1646 if (RT_SUCCESS(rc))
1647 rc = ShClTransferObjClose(pTransfer, hObj);
1648 break;
1649 }
1650
1651 case VBOX_SHCL_GUEST_FN_OBJ_READ:
1652 {
1653 if (cParms != VBOX_SHCL_CPARMS_OBJ_READ)
1654 break;
1655
1656 SHCLOBJHANDLE hObj;
1657 rc = HGCMSvcGetU64(&paParms[1], &hObj); /* Get object handle. */
1658
1659 uint32_t cbToRead = 0;
1660 if (RT_SUCCESS(rc))
1661 rc = HGCMSvcGetU32(&paParms[2], &cbToRead);
1662
1663 void *pvBuf = NULL;
1664 uint32_t cbBuf = 0;
1665 if (RT_SUCCESS(rc))
1666 rc = HGCMSvcGetPv(&paParms[3], &pvBuf, &cbBuf);
1667
1668 LogFlowFunc(("hObj=%RU64, cbBuf=%RU32, cbToRead=%RU32, rc=%Rrc\n", hObj, cbBuf, cbToRead, rc));
1669
1670 if ( RT_SUCCESS(rc)
1671 && ( !cbBuf
1672 || !cbToRead
1673 || cbBuf < cbToRead
1674 )
1675 )
1676 {
1677 rc = VERR_INVALID_PARAMETER;
1678 }
1679
1680 if (RT_SUCCESS(rc))
1681 {
1682 uint32_t cbRead;
1683 rc = ShClTransferObjRead(pTransfer, hObj, pvBuf, cbToRead, &cbRead, 0 /* fFlags */);
1684 if (RT_SUCCESS(rc))
1685 {
1686 HGCMSvcSetU32(&paParms[3], cbRead);
1687
1688 /** @todo Implement checksum support. */
1689 }
1690 }
1691 break;
1692 }
1693
1694 case VBOX_SHCL_GUEST_FN_OBJ_WRITE:
1695 {
1696 SHCLOBJDATACHUNK dataChunk;
1697 rc = shclSvcTransferGetObjDataChunk(cParms, paParms, &dataChunk);
1698 if (RT_SUCCESS(rc))
1699 {
1700 void *pvData = ShClTransferObjDataChunkDup(&dataChunk);
1701 uint32_t cbData = sizeof(SHCLOBJDATACHUNK);
1702
1703 const SHCLEVENTID uEvent = VBOX_SHCL_CONTEXTID_GET_EVENT(uCID);
1704
1705 PSHCLEVENTPAYLOAD pPayload;
1706 rc = ShClPayloadAlloc(uEvent, pvData, cbData, &pPayload);
1707 if (RT_SUCCESS(rc))
1708 {
1709 rc = ShClEventSignal(&pTransfer->Events, uEvent, pPayload);
1710 if (RT_FAILURE(rc))
1711 ShClPayloadFree(pPayload);
1712 }
1713 }
1714
1715 break;
1716 }
1717
1718 default:
1719 rc = VERR_NOT_IMPLEMENTED;
1720 break;
1721 }
1722
1723 LogFlowFunc(("[Client %RU32] Returning rc=%Rrc\n", pClient->State.uClientID, rc));
1724 return rc;
1725}
1726
1727/**
1728 * Transfer host handler for the Shared Clipboard host service.
1729 *
1730 * @returns VBox status code.
1731 * @param u32Function Function number being called.
1732 * @param cParms Number of function parameters supplied.
1733 * @param paParms Array function parameters supplied.
1734 */
1735int shclSvcTransferHostHandler(uint32_t u32Function,
1736 uint32_t cParms,
1737 VBOXHGCMSVCPARM paParms[])
1738{
1739 RT_NOREF(cParms, paParms);
1740
1741 int rc = VERR_NOT_IMPLEMENTED; /* Play safe. */
1742
1743 switch (u32Function)
1744 {
1745 case VBOX_SHCL_HOST_FN_CANCEL: /** @todo Implement this. */
1746 break;
1747
1748 case VBOX_SHCL_HOST_FN_ERROR: /** @todo Implement this. */
1749 break;
1750
1751 default:
1752 break;
1753
1754 }
1755
1756 LogFlowFuncLeaveRC(rc);
1757 return rc;
1758}
1759
1760/**
1761 * Registers an clipboard transfer area.
1762 *
1763 * @returns VBox status code.
1764 * @param pClientState Client state to use.
1765 * @param pTransfer Shared Clipboard transfer to register a clipboard area for.
1766 */
1767int shclSvcTransferAreaRegister(PSHCLCLIENTSTATE pClientState, PSHCLTRANSFER pTransfer)
1768{
1769 RT_NOREF(pClientState);
1770
1771 LogFlowFuncEnter();
1772
1773 AssertMsgReturn(pTransfer->pArea == NULL, ("An area already is registered for this transfer\n"),
1774 VERR_WRONG_ORDER);
1775
1776 pTransfer->pArea = new SharedClipboardArea();
1777 if (!pTransfer->pArea)
1778 return VERR_NO_MEMORY;
1779
1780 int rc;
1781
1782 if (g_ExtState.pfnExtension)
1783 {
1784 SHCLEXTAREAPARMS parms;
1785 RT_ZERO(parms);
1786
1787 parms.uID = NIL_SHCLAREAID;
1788
1789 /* As the meta data is now complete, register a new clipboard on the host side. */
1790 rc = g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_AREA_REGISTER, &parms, sizeof(parms));
1791 if (RT_SUCCESS(rc))
1792 {
1793 /* Note: Do *not* specify SHCLAREA_OPEN_FLAGS_MUST_NOT_EXIST as flags here, as VBoxSVC took care of the
1794 * clipboard area creation already. */
1795 rc = pTransfer->pArea->OpenTemp(parms.uID /* Area ID */,
1796 SHCLAREA_OPEN_FLAGS_NONE);
1797 }
1798
1799 LogFlowFunc(("Registered new clipboard area (%RU32) by client %RU32 with rc=%Rrc\n",
1800 parms.uID, pClientState->uClientID, rc));
1801 }
1802 else
1803 rc = VERR_NOT_SUPPORTED;
1804
1805 LogFlowFuncLeaveRC(rc);
1806 return rc;
1807}
1808
1809/**
1810 * Unregisters an clipboard transfer area.
1811 *
1812 * @returns VBox status code.
1813 * @param pClientState Client state to use.
1814 * @param pTransfer Shared Clipboard transfer to unregister a clipboard area from.
1815 */
1816int shclSvcTransferAreaUnregister(PSHCLCLIENTSTATE pClientState, PSHCLTRANSFER pTransfer)
1817{
1818 RT_NOREF(pClientState);
1819
1820 LogFlowFuncEnter();
1821
1822 if (!pTransfer->pArea)
1823 return VINF_SUCCESS;
1824
1825 int rc = VINF_SUCCESS;
1826
1827 if (g_ExtState.pfnExtension)
1828 {
1829 SHCLEXTAREAPARMS parms;
1830 RT_ZERO(parms);
1831
1832 parms.uID = pTransfer->pArea->GetID();
1833
1834 rc = g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_AREA_UNREGISTER, &parms, sizeof(parms));
1835 if (RT_SUCCESS(rc))
1836 {
1837 rc = pTransfer->pArea->Close();
1838 if (RT_SUCCESS(rc))
1839 {
1840 delete pTransfer->pArea;
1841 pTransfer->pArea = NULL;
1842 }
1843 }
1844
1845 LogFlowFunc(("Unregistered clipboard area (%RU32) by client %RU32 with rc=%Rrc\n",
1846 parms.uID, pClientState->uClientID, rc));
1847 }
1848
1849 delete pTransfer->pArea;
1850 pTransfer->pArea = NULL;
1851
1852 LogFlowFuncLeaveRC(rc);
1853 return rc;
1854}
1855
1856/**
1857 * Attaches to an existing (registered) clipboard transfer area.
1858 *
1859 * @returns VBox status code.
1860 * @param pClientState Client state to use.
1861 * @param pTransfer Shared Clipboard transfer to attach a clipboard area to.
1862 * @param uID ID of clipboard area to to attach to. Specify 0 to attach to the most recent one.
1863 */
1864int shclSvcTransferAreaAttach(PSHCLCLIENTSTATE pClientState, PSHCLTRANSFER pTransfer,
1865 SHCLAREAID uID)
1866{
1867 RT_NOREF(pClientState);
1868
1869 LogFlowFuncEnter();
1870
1871 AssertMsgReturn(pTransfer->pArea == NULL, ("An area already is attached to this transfer\n"),
1872 VERR_WRONG_ORDER);
1873
1874 pTransfer->pArea = new SharedClipboardArea();
1875 if (!pTransfer->pArea)
1876 return VERR_NO_MEMORY;
1877
1878 int rc = VINF_SUCCESS;
1879
1880 if (g_ExtState.pfnExtension)
1881 {
1882 SHCLEXTAREAPARMS parms;
1883 RT_ZERO(parms);
1884
1885 parms.uID = uID; /* 0 means most recent clipboard area. */
1886
1887 /* The client now needs to attach to the most recent clipboard area
1888 * to keep a reference to it. The host does the actual book keeping / cleanup then.
1889 *
1890 * This might fail if the host does not have a most recent clipboard area (yet). */
1891 rc = g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_AREA_ATTACH, &parms, sizeof(parms));
1892 if (RT_SUCCESS(rc))
1893 rc = pTransfer->pArea->OpenTemp(parms.uID /* Area ID */);
1894
1895 LogFlowFunc(("Attached client %RU32 to clipboard area %RU32 with rc=%Rrc\n",
1896 pClientState->uClientID, parms.uID, rc));
1897 }
1898 else
1899 rc = VERR_NOT_SUPPORTED;
1900
1901 LogFlowFuncLeaveRC(rc);
1902 return rc;
1903}
1904
1905/**
1906 * Detaches from an clipboard transfer area.
1907 *
1908 * @returns VBox status code.
1909 * @param pClientState Client state to use.
1910 * @param pTransfer Shared Clipboard transfer to detach a clipboard area from.
1911 */
1912int shclSvcTransferAreaDetach(PSHCLCLIENTSTATE pClientState, PSHCLTRANSFER pTransfer)
1913{
1914 RT_NOREF(pClientState);
1915
1916 LogFlowFuncEnter();
1917
1918 if (!pTransfer->pArea)
1919 return VINF_SUCCESS;
1920
1921 const uint32_t uAreaID = pTransfer->pArea->GetID();
1922
1923 int rc = VINF_SUCCESS;
1924
1925 if (g_ExtState.pfnExtension)
1926 {
1927 SHCLEXTAREAPARMS parms;
1928 RT_ZERO(parms);
1929 parms.uID = uAreaID;
1930
1931 rc = g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_AREA_DETACH, &parms, sizeof(parms));
1932
1933 LogFlowFunc(("Detached client %RU32 from clipboard area %RU32 with rc=%Rrc\n",
1934 pClientState->uClientID, uAreaID, rc));
1935 }
1936
1937 delete pTransfer->pArea;
1938 pTransfer->pArea = NULL;
1939
1940 LogFlowFuncLeaveRC(rc);
1941 return rc;
1942}
1943
1944/**
1945 * Reports a transfer status to the guest.
1946 *
1947 * @returns VBox status code.
1948 * @param pClient Client that owns the transfer.
1949 * @param pTransfer Transfer to report status for.
1950 * @param uStatus Status to report.
1951 * @param rcTransfer Result code to report. Optional and depending on status.
1952 * @param puEvent Where to store the created wait event. Optional.
1953 */
1954int shclSvcTransferSendStatus(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, SHCLTRANSFERSTATUS uStatus,
1955 int rcTransfer, PSHCLEVENTID puEvent)
1956{
1957 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
1958 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1959 /* puEvent is optional. */
1960
1961 PSHCLCLIENTMSG pMsgReadData = shclSvcMsgAlloc(VBOX_SHCL_HOST_MSG_TRANSFER_STATUS,
1962 VBOX_SHCL_CPARMS_TRANSFER_STATUS);
1963 if (!pMsgReadData)
1964 return VERR_NO_MEMORY;
1965
1966 const SHCLEVENTID uEvent = ShClEventIDGenerate(&pTransfer->Events);
1967
1968 HGCMSvcSetU64(&pMsgReadData->paParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
1969 pTransfer->State.uID, uEvent));
1970 HGCMSvcSetU32(&pMsgReadData->paParms[1], pTransfer->State.enmDir);
1971 HGCMSvcSetU32(&pMsgReadData->paParms[2], uStatus);
1972 HGCMSvcSetU32(&pMsgReadData->paParms[3], (uint32_t)rcTransfer); /** @todo uint32_t vs. int. */
1973 HGCMSvcSetU32(&pMsgReadData->paParms[4], 0 /* fFlags, unused */);
1974
1975 int rc = shclSvcMsgAdd(pClient, pMsgReadData, true /* fAppend */);
1976 if (RT_SUCCESS(rc))
1977 {
1978 rc = ShClEventRegister(&pTransfer->Events, uEvent);
1979 if (RT_SUCCESS(rc))
1980 {
1981 rc = shclSvcClientWakeup(pClient);
1982 if (RT_SUCCESS(rc))
1983 {
1984 LogRel2(("Shared Clipboard: Reported status %s (rc=%Rrc) of transfer %RU32 to guest\n",
1985 ShClTransferStatusToStr(uStatus), rcTransfer, pTransfer->State.uID));
1986
1987 if (puEvent)
1988 *puEvent = uEvent;
1989 }
1990 else
1991 ShClEventUnregister(&pTransfer->Events, uEvent);
1992 }
1993 }
1994
1995 LogFlowFuncLeaveRC(rc);
1996 return rc;
1997}
1998
1999/**
2000 * Starts a new transfer, waiting for acknowledgement by the guest side.
2001 *
2002 * @returns VBox status code.
2003 * @param pClient Client that owns the transfer.
2004 * @param enmDir Transfer direction to start.
2005 * @param enmSource Transfer source to start.
2006 * @param ppTransfer Where to return the created transfer on success. Optional.
2007 */
2008int shclSvcTransferStart(PSHCLCLIENT pClient,
2009 SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource,
2010 PSHCLTRANSFER *ppTransfer)
2011{
2012 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
2013 /* ppTransfer is optional. */
2014
2015 LogFlowFuncEnter();
2016
2017 ShClTransferCtxCleanup(&pClient->TransferCtx);
2018
2019 int rc;
2020
2021 if (!ShClTransferCtxTransfersMaximumReached(&pClient->TransferCtx))
2022 {
2023 LogRel2(("Shared Clipboard: Starting %s transfer ...\n", enmDir == SHCLTRANSFERDIR_READ ? "read" : "write"));
2024
2025 PSHCLTRANSFER pTransfer;
2026 rc = ShClTransferCreate(&pTransfer);
2027 if (RT_SUCCESS(rc))
2028 {
2029 rc = ShClSvcImplTransferCreate(pClient, pTransfer);
2030 if (RT_SUCCESS(rc))
2031 {
2032 SHCLPROVIDERCREATIONCTX creationCtx;
2033 RT_ZERO(creationCtx);
2034
2035 if (enmDir == SHCLTRANSFERDIR_READ)
2036 {
2037 rc = shclSvcTransferAreaRegister(&pClient->State, pTransfer);
2038 if (RT_SUCCESS(rc))
2039 {
2040 creationCtx.Interface.pfnTransferOpen = shclSvcTransferIfaceOpen;
2041 creationCtx.Interface.pfnTransferClose = shclSvcTransferIfaceClose;
2042
2043 creationCtx.Interface.pfnRootsGet = shclSvcTransferIfaceGetRoots;
2044
2045 creationCtx.Interface.pfnListOpen = shclSvcTransferIfaceListOpen;
2046 creationCtx.Interface.pfnListClose = shclSvcTransferIfaceListClose;
2047 creationCtx.Interface.pfnListHdrRead = shclSvcTransferIfaceListHdrRead;
2048 creationCtx.Interface.pfnListEntryRead = shclSvcTransferIfaceListEntryRead;
2049
2050 creationCtx.Interface.pfnObjOpen = shclSvcTransferIfaceObjOpen;
2051 creationCtx.Interface.pfnObjClose = shclSvcTransferIfaceObjClose;
2052 creationCtx.Interface.pfnObjRead = shclSvcTransferIfaceObjRead;
2053 }
2054 }
2055 else if (enmDir == SHCLTRANSFERDIR_WRITE)
2056 {
2057 creationCtx.Interface.pfnListHdrWrite = shclSvcTransferIfaceListHdrWrite;
2058 creationCtx.Interface.pfnListEntryWrite = shclSvcTransferIfaceListEntryWrite;
2059 creationCtx.Interface.pfnObjWrite = shclSvcTransferIfaceObjWrite;
2060 }
2061 else
2062 AssertFailed();
2063
2064 creationCtx.enmSource = pClient->State.enmSource;
2065 creationCtx.pvUser = pClient;
2066
2067 uint32_t uTransferID = 0;
2068
2069 rc = ShClTransferSetInterface(pTransfer, &creationCtx);
2070 if (RT_SUCCESS(rc))
2071 {
2072 rc = ShClTransferCtxTransferRegister(&pClient->TransferCtx, pTransfer, &uTransferID);
2073 if (RT_SUCCESS(rc))
2074 {
2075 rc = ShClTransferInit(pTransfer, uTransferID, enmDir, enmSource);
2076 if (RT_SUCCESS(rc))
2077 {
2078 if ( enmSource == SHCLSOURCE_LOCAL
2079 && enmDir == SHCLTRANSFERDIR_WRITE) /* Get roots if this is a local write transfer. */
2080 {
2081 rc = ShClSvcImplTransferGetRoots(pClient, pTransfer);
2082 }
2083
2084 if (RT_SUCCESS(rc))
2085 rc = ShClTransferStart(pTransfer);
2086
2087 if (RT_SUCCESS(rc))
2088 {
2089 SHCLEVENTID uEvent;
2090 rc = shclSvcTransferSendStatus(pClient, pTransfer,
2091 SHCLTRANSFERSTATUS_INITIALIZED, VINF_SUCCESS,
2092 &uEvent);
2093 if (RT_SUCCESS(rc))
2094 {
2095 LogRel2(("Shared Clipboard: Waiting for start of transfer %RU32 on guest ...\n",
2096 pTransfer->State.uID));
2097
2098 PSHCLEVENTPAYLOAD pPayload;
2099 rc = ShClEventWait(&pTransfer->Events, uEvent, pTransfer->uTimeoutMs, &pPayload);
2100 if (RT_SUCCESS(rc))
2101 {
2102 Assert(pPayload->cbData == sizeof(SHCLREPLY));
2103 PSHCLREPLY pReply = (PSHCLREPLY)pPayload->pvData;
2104 AssertPtr(pReply);
2105
2106 Assert(pReply->uType == VBOX_SHCL_REPLYMSGTYPE_TRANSFER_STATUS);
2107
2108 if (pReply->u.TransferStatus.uStatus == SHCLTRANSFERSTATUS_STARTED)
2109 {
2110 LogRel2(("Shared Clipboard: Started transfer %RU32 on guest\n", pTransfer->State.uID));
2111 }
2112 else
2113 LogRel(("Shared Clipboard: Guest reported status %s (error %Rrc) while starting transfer %RU32\n",
2114 ShClTransferStatusToStr(pReply->u.TransferStatus.uStatus),
2115 pReply->rc, pTransfer->State.uID));
2116 }
2117 else
2118 LogRel(("Shared Clipboard: Unable to start transfer %RU32 on guest, rc=%Rrc\n",
2119 pTransfer->State.uID, rc));
2120 }
2121 }
2122 }
2123
2124 if (RT_FAILURE(rc))
2125 ShClTransferCtxTransferUnregister(&pClient->TransferCtx, uTransferID);
2126 }
2127 }
2128 }
2129
2130 if (RT_FAILURE(rc))
2131 {
2132 ShClSvcImplTransferDestroy(pClient, pTransfer);
2133 ShClTransferDestroy(pTransfer);
2134
2135 RTMemFree(pTransfer);
2136 pTransfer = NULL;
2137 }
2138 else
2139 {
2140 if (ppTransfer)
2141 *ppTransfer = pTransfer;
2142 }
2143 }
2144
2145 if (RT_FAILURE(rc))
2146 LogRel(("Shared Clipboard: Starting transfer failed with %Rrc\n", rc));
2147 }
2148 else
2149 rc = VERR_SHCLPB_MAX_TRANSFERS_REACHED;
2150
2151 LogFlowFuncLeaveRC(rc);
2152 return rc;
2153}
2154
2155/**
2156 * Stops (and destroys) a transfer, communicating the status to the guest side.
2157 *
2158 * @returns VBox status code.
2159 * @param pClient Client that owns the transfer.
2160 * @param pTransfer Transfer to stop.
2161 */
2162int shclSvcTransferStop(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
2163{
2164 SHCLEVENTID uEvent;
2165 int rc = shclSvcTransferSendStatus(pClient, pTransfer,
2166 SHCLTRANSFERSTATUS_STOPPED, VINF_SUCCESS,
2167 &uEvent);
2168 if (RT_SUCCESS(rc))
2169 {
2170 LogRel2(("Shared Clipboard: Waiting for stop of transfer %RU32 on guest ...\n", pTransfer->State.uID));
2171
2172 rc = ShClEventWait(&pTransfer->Events, uEvent, pTransfer->uTimeoutMs, NULL);
2173 if (RT_SUCCESS(rc))
2174 LogRel2(("Shared Clipboard: Stopped transfer %RU32 on guest\n", pTransfer->State.uID));
2175 }
2176
2177 if (RT_FAILURE(rc))
2178 LogRel(("Shared Clipboard: Unable to stop transfer %RU32 on guest, rc=%Rrc\n",
2179 pTransfer->State.uID, rc));
2180
2181 /* Regardless of whether the guest was able to report back and/or stop the transfer, remove the transfer on the host
2182 * so that we don't risk of having stale transfers here. */
2183 int rc2 = ShClTransferCtxTransferUnregister(&pClient->TransferCtx, ShClTransferGetID(pTransfer));
2184 if (RT_SUCCESS(rc2))
2185 {
2186 ShClTransferDestroy(pTransfer);
2187 pTransfer = NULL;
2188 }
2189
2190 LogFlowFuncLeaveRC(rc);
2191 return rc;
2192}
2193
2194/**
2195 * Sets the host service's (file) transfer mode.
2196 *
2197 * @returns VBox status code.
2198 * @param fMode Transfer mode to set.
2199 */
2200int shclSvcTransferModeSet(uint32_t fMode)
2201{
2202 if (fMode & ~VBOX_SHCL_TRANSFER_MODE_VALID_MASK)
2203 return VERR_INVALID_FLAGS;
2204
2205 g_fTransferMode = fMode;
2206
2207 LogRel2(("Shared Clipboard: Transfer mode set to 0x%x\n", g_fTransferMode));
2208
2209 /* If file transfers are being disabled, make sure to also reset (destroy) all pending transfers. */
2210 if (g_fTransferMode == VBOX_SHCL_TRANSFER_MODE_DISABLED)
2211 {
2212 ClipboardClientMap::const_iterator itClient = g_mapClients.begin();
2213 while (itClient != g_mapClients.end())
2214 {
2215 PSHCLCLIENT pClient = itClient->second;
2216 AssertPtr(pClient);
2217
2218 shclSvcClientTransfersReset(pClient);
2219
2220 ++itClient;
2221 }
2222 }
2223
2224 LogFlowFuncLeaveRC(VINF_SUCCESS);
2225 return VINF_SUCCESS;
2226}
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