VirtualBox

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

Last change on this file since 100347 was 100291, checked in by vboxsync, 21 months ago

Shared Clipboard: Renaming (ShClTransferCtxTransferUnregister() -> ShClTransferCtxTransferUnregisterById()). 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 100291 2023-06-26 08:10:29Z 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 ShClTransferCtxTransferUnregisterById(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 ShClTransferCtxTransferUnregisterById(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 = ShClTransferCtxTransferUnregisterById(&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