VirtualBox

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

Last change on this file since 100524 was 100499, checked in by vboxsync, 18 months ago

Shared Clipboard: List entry reading fixes. bugref:9437

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