VirtualBox

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

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

Copyright year updates by scm.

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

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