VirtualBox

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

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

Shared Clipboard/Transfers: Removed some superfluous HGCM parameters. Untested.

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