VirtualBox

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

Last change on this file since 100204 was 100204, checked in by vboxsync, 23 months ago

Shared Clipboard: Unified root list entry code to also use the generic list entry code, a lot of updates for the cross OS transfer handling code, more updates for HTTP server transfer handling.

This also changed the handling of how that transfers are being initiated, as we needed to have this for X11: Before, transfers were initiated as soon as on side announced the URI list format -- now we postpone initiating the transfer until the receiving side requests the data as URI list.

bugref:9437

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette