VirtualBox

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

Last change on this file since 100765 was 100667, checked in by vboxsync, 17 months ago

Shared Clipboard: Logging nits. bugref:9437

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