VirtualBox

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

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

Shared Clipboard/HostService: Renaming to match terminology (*SvcImpl* -> *Backend*).

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