VirtualBox

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

最後變更 在這個檔案從100370是 100370,由 vboxsync 提交於 21 月 前

Shared Clipboard: Removed ShClBackendTransferHGRootListRead(), not needed. ​​bugref:9437

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 87.6 KB
 
1/* $Id: VBoxSharedClipboardSvc-transfers.cpp 100370 2023-07-05 07:14:28Z 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.alldomusa.eu.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 shClSvcTransferSendStatusAsyncInternal(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 pListEntry Pointer list entry to set.
1281 */
1282static int shClSvcTransferSetListEntry(uint32_t cParms, VBOXHGCMSVCPARM aParms[],
1283 PSHCLLISTENTRY pListEntry)
1284{
1285 int rc;
1286
1287 /* Sanity. */
1288 AssertReturn(ShClTransferListEntryIsValid(pListEntry), VERR_INVALID_PARAMETER);
1289
1290 if (cParms == VBOX_SHCL_CPARMS_LIST_ENTRY)
1291 {
1292 HGCMSvcSetPv (&aParms[3], pListEntry->pszName, pListEntry->cbName);
1293 HGCMSvcSetU32(&aParms[4], pListEntry->cbInfo);
1294 HGCMSvcSetPv (&aParms[5], pListEntry->pvInfo, pListEntry->cbInfo);
1295
1296 rc = VINF_SUCCESS;
1297 }
1298 else
1299 rc = VERR_INVALID_PARAMETER;
1300
1301 LogFlowFuncLeaveRC(rc);
1302 return rc;
1303}
1304
1305/**
1306 * Gets a transfer object data chunk from 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 pDataChunk Where to store the object data chunk data.
1312 */
1313static int shClSvcTransferGetObjDataChunk(uint32_t cParms, VBOXHGCMSVCPARM aParms[], PSHCLOBJDATACHUNK pDataChunk)
1314{
1315 AssertPtrReturn(aParms, VERR_INVALID_PARAMETER);
1316 AssertPtrReturn(pDataChunk, VERR_INVALID_PARAMETER);
1317
1318 int rc;
1319
1320 if (cParms == VBOX_SHCL_CPARMS_OBJ_WRITE)
1321 {
1322 rc = HGCMSvcGetU64(&aParms[1], &pDataChunk->uHandle);
1323 if (RT_SUCCESS(rc))
1324 {
1325 uint32_t cbToRead;
1326 rc = HGCMSvcGetU32(&aParms[2], &cbToRead);
1327 if (RT_SUCCESS(rc))
1328 {
1329 rc = HGCMSvcGetPv(&aParms[3], &pDataChunk->pvData, &pDataChunk->cbData);
1330 if (RT_SUCCESS(rc))
1331 rc = cbToRead == pDataChunk->cbData ? VINF_SUCCESS : VERR_INVALID_PARAMETER;
1332 }
1333
1334 /** @todo Implement checksum handling. */
1335 }
1336 }
1337 else
1338 rc = VERR_INVALID_PARAMETER;
1339
1340 LogFlowFuncLeaveRC(rc);
1341 return rc;
1342}
1343
1344/**
1345 * Handles a guest reply (VBOX_SHCL_GUEST_FN_REPLY) message.
1346 *
1347 * @returns VBox status code.
1348 * @param pClient Pointer to associated client.
1349 * @param idTransfer Transfer ID supplied from the guest.
1350 * @param cParms Number of function parameters supplied.
1351 * @param aParms Array function parameters supplied.
1352 */
1353static int shClSvcTransferHandleReply(PSHCLCLIENT pClient, SHCLTRANSFERID idTransfer, uint32_t cParms, VBOXHGCMSVCPARM aParms[])
1354{
1355 int rc;
1356
1357 PSHCLTRANSFER pTransfer = NULL;
1358
1359 uint32_t cbReply = sizeof(SHCLREPLY);
1360 PSHCLREPLY pReply = (PSHCLREPLY)RTMemAlloc(cbReply);
1361 if (pReply)
1362 {
1363 rc = shClSvcTransferGetReply(cParms, aParms, pReply);
1364 if (RT_SUCCESS(rc))
1365 {
1366 if ( pReply->uType == VBOX_SHCL_TX_REPLYMSGTYPE_TRANSFER_STATUS
1367 && pReply->u.TransferStatus.uStatus == SHCLTRANSFERSTATUS_REQUESTED)
1368 {
1369 /* SHCLTRANSFERSTATUS_REQUESTED is special, as it doesn't provide a transfer ID. */
1370 }
1371 else /* Everything else needs a valid transfer ID. */
1372 {
1373 pTransfer = ShClTransferCtxGetTransferById(&pClient->Transfers.Ctx, idTransfer);
1374 if (!pTransfer)
1375 {
1376 LogRel2(("Shared Clipboard: Transfer with ID %RU16 not found\n", idTransfer));
1377 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
1378 }
1379 }
1380
1381 if (RT_FAILURE(rc))
1382 {
1383 RTMemFree(pReply);
1384 pReply = NULL;
1385
1386 return rc;
1387 }
1388
1389 PSHCLEVENTPAYLOAD pPayload
1390 = (PSHCLEVENTPAYLOAD)RTMemAlloc(sizeof(SHCLEVENTPAYLOAD));
1391 if (pPayload)
1392 {
1393 pPayload->pvData = pReply;
1394 pPayload->cbData = cbReply;
1395
1396 switch (pReply->uType)
1397 {
1398 case VBOX_SHCL_TX_REPLYMSGTYPE_TRANSFER_STATUS:
1399 {
1400 /* SHCLTRANSFERSTATUS_REQUESTED is special, as it doesn't provide a transfer ID. */
1401 if (SHCLTRANSFERSTATUS_REQUESTED == pReply->u.TransferStatus.uStatus)
1402 {
1403 LogRel2(("Shared Clipboard: Guest requested a new host -> guest transfer\n"));
1404 }
1405 else
1406 LogRel2(("Shared Clipboard: Guest reported status %s for transfer %RU32\n",
1407 ShClTransferStatusToStr(pReply->u.TransferStatus.uStatus), idTransfer));
1408
1409 switch (pReply->u.TransferStatus.uStatus)
1410 {
1411 case SHCLTRANSFERSTATUS_REQUESTED: /* Guest requests a H->G transfer. */
1412 {
1413 uint32_t const uMode = ShClSvcGetMode();
1414 if ( uMode == VBOX_SHCL_MODE_HOST_TO_GUEST
1415 || uMode == VBOX_SHCL_MODE_BIDIRECTIONAL)
1416 {
1417 /* We only create (but not initialize) the transfer here. This is the most lightweight form of
1418 * having a pending transfer around. Report back the new transfer ID to the guest then. */
1419 if (pTransfer == NULL) /* Must not exist yet. */
1420 {
1421 rc = ShClSvcTransferCreate(pClient, SHCLTRANSFERDIR_TO_REMOTE, SHCLSOURCE_LOCAL,
1422 NIL_SHCLTRANSFERID /* Creates a new transfer ID */,
1423 &pTransfer);
1424 if (RT_SUCCESS(rc))
1425 {
1426 shClSvcClientLock(pClient);
1427
1428 rc = shClSvcTransferSendStatusAsyncInternal(pClient, pTransfer,
1429 SHCLTRANSFERSTATUS_REQUESTED, VINF_SUCCESS,
1430 NULL);
1431 shClSvcClientUnlock(pClient);
1432 }
1433 }
1434 else
1435 rc = VERR_WRONG_ORDER;
1436 }
1437 else
1438 rc = VERR_INVALID_PARAMETER;
1439
1440 break;
1441 }
1442
1443 case SHCLTRANSFERSTATUS_INITIALIZED: /* Guest reports the transfer as being initialized. */
1444 {
1445 switch (ShClTransferGetDir(pTransfer))
1446 {
1447 case SHCLTRANSFERDIR_FROM_REMOTE: /* G->H */
1448 /* Already done locally when creating the transfer. */
1449 break;
1450
1451 case SHCLTRANSFERDIR_TO_REMOTE: /* H->G */
1452 {
1453 /* Initialize the transfer on the host side. */
1454 rc = ShClSvcTransferInit(pClient, pTransfer);
1455 break;
1456 }
1457
1458 default:
1459 AssertFailed();
1460 break;
1461 }
1462
1463 break;
1464 }
1465 case SHCLTRANSFERSTATUS_STARTED: /* Guest has started the transfer on its side. */
1466 {
1467 /* We only need to start for H->G transfers here.
1468 * For G->H transfers we start this as soon as the host clipboard requests data. */
1469 if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_TO_REMOTE)
1470 {
1471 /* Start the transfer on the host side. */
1472 rc = ShClSvcTransferStart(pClient, pTransfer);
1473 }
1474 break;
1475 }
1476
1477 case SHCLTRANSFERSTATUS_CANCELED:
1478 RT_FALL_THROUGH();
1479 case SHCLTRANSFERSTATUS_KILLED:
1480 {
1481 LogRel(("Shared Clipboard: Guest has %s transfer %RU32\n",
1482 pReply->uType == SHCLTRANSFERSTATUS_CANCELED ? "canceled" : "killed", pTransfer->State.uID));
1483
1484 rc = ShClSvcTransferStop(pClient, pTransfer, false /* fWaitForGuest */);
1485
1486 /* Regardless of whether the guest was able to report back and/or stop the transfer, remove the transfer on the host
1487 * so that we don't risk of having stale transfers here. */
1488 ShClSvcTransferDestroy(pClient, pTransfer);
1489 pTransfer = NULL;
1490 break;
1491 }
1492
1493 case SHCLTRANSFERSTATUS_STOPPED:
1494 {
1495 LogRel(("Shared Clipboard: Guest has stopped transfer %RU32\n", pTransfer->State.uID));
1496
1497 rc = ShClSvcTransferStop(pClient, pTransfer, false /* fWaitForGuest */);
1498 break;
1499 }
1500
1501 case SHCLTRANSFERSTATUS_ERROR:
1502 {
1503 LogRel(("Shared Clipboard: Guest reported error %Rrc for transfer %RU32\n",
1504 pReply->rc, pTransfer->State.uID));
1505 RT_FALL_THROUGH();
1506 }
1507 default:
1508 {
1509 /* Regardless of whether the guest was able to report back and/or stop the transfer, remove the transfer on the host
1510 * so that we don't risk of having stale transfers here. */
1511 ShClSvcTransferDestroy(pClient, pTransfer);
1512 pTransfer = NULL;
1513 break;
1514 }
1515 }
1516
1517 /* Tell the backend. */
1518 int rc2 = ShClBackendTransferHandleStatusReply(pClient->pBackend, pClient, pTransfer,
1519 SHCLSOURCE_REMOTE, pReply->u.TransferStatus.uStatus,
1520 pReply->rc);
1521 if (RT_SUCCESS(rc))
1522 rc = rc2;
1523
1524 RT_FALL_THROUGH();
1525 }
1526 case VBOX_SHCL_TX_REPLYMSGTYPE_LIST_OPEN:
1527 RT_FALL_THROUGH();
1528 case VBOX_SHCL_TX_REPLYMSGTYPE_LIST_CLOSE:
1529 RT_FALL_THROUGH();
1530 case VBOX_SHCL_TX_REPLYMSGTYPE_OBJ_OPEN:
1531 RT_FALL_THROUGH();
1532 case VBOX_SHCL_TX_REPLYMSGTYPE_OBJ_CLOSE:
1533 {
1534 uint64_t uCID;
1535 rc = HGCMSvcGetU64(&aParms[0], &uCID);
1536 if (RT_SUCCESS(rc))
1537 {
1538 const PSHCLEVENT pEvent
1539 = ShClEventSourceGetFromId(&pClient->EventSrc, VBOX_SHCL_CONTEXTID_GET_EVENT(uCID));
1540 if (pEvent)
1541 {
1542 LogFlowFunc(("uCID=%RU64 -> idEvent=%RU32\n", uCID, pEvent->idEvent));
1543
1544 rc = ShClEventSignal(pEvent, pPayload);
1545 }
1546 /** @todo Silently skip? */
1547 }
1548 break;
1549 }
1550
1551 default:
1552 rc = VERR_NOT_FOUND;
1553 break;
1554 }
1555
1556 if (RT_FAILURE(rc))
1557 {
1558 if (pPayload)
1559 RTMemFree(pPayload);
1560 }
1561 }
1562 else
1563 rc = VERR_NO_MEMORY;
1564 }
1565 }
1566 else
1567 rc = VERR_NO_MEMORY;
1568
1569 if (RT_FAILURE(rc))
1570 {
1571 if (pReply)
1572 RTMemFree(pReply);
1573 }
1574
1575 LogFlowFuncLeaveRC(rc);
1576 return rc;
1577}
1578
1579/**
1580 * Transfer client (guest) handler for the Shared Clipboard host service.
1581 *
1582 * @returns VBox status code, or VINF_HGCM_ASYNC_EXECUTE if returning to the client will be deferred.
1583 * @param pClient Pointer to associated client.
1584 * @param callHandle The client's call handle of this call.
1585 * @param u32Function Function number being called.
1586 * @param cParms Number of function parameters supplied.
1587 * @param aParms Array function parameters supplied.
1588 * @param tsArrival Timestamp of arrival.
1589 */
1590int shClSvcTransferHandler(PSHCLCLIENT pClient,
1591 VBOXHGCMCALLHANDLE callHandle,
1592 uint32_t u32Function,
1593 uint32_t cParms,
1594 VBOXHGCMSVCPARM aParms[],
1595 uint64_t tsArrival)
1596{
1597 RT_NOREF(callHandle, aParms, tsArrival);
1598
1599 LogFlowFunc(("uClient=%RU32, u32Function=%RU32 (%s), cParms=%RU32, g_ExtState.pfnExtension=%p\n",
1600 pClient->State.uClientID, u32Function, ShClGuestMsgToStr(u32Function), cParms, g_ExtState.pfnExtension));
1601
1602 /* Check if we've the right mode set. */
1603 if (!shClSvcTransferMsgIsAllowed(ShClSvcGetMode(), u32Function))
1604 {
1605 LogFunc(("Wrong clipboard mode, denying access\n"));
1606 return VERR_ACCESS_DENIED;
1607 }
1608
1609 int rc = VERR_INVALID_PARAMETER; /* Play safe by default. */
1610
1611 if (cParms < 1)
1612 return rc;
1613 ASSERT_GUEST_RETURN(aParms[0].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE);
1614
1615 uint64_t uCID = 0; /* Context ID */
1616 rc = HGCMSvcGetU64(&aParms[0], &uCID);
1617 if (RT_FAILURE(rc))
1618 return rc;
1619
1620 const SHCLTRANSFERID idTransfer = VBOX_SHCL_CONTEXTID_GET_TRANSFER(uCID);
1621
1622 /*
1623 * Pre-check: For certain messages we need to make sure that a (right) transfer is present.
1624 */
1625 PSHCLTRANSFER pTransfer = NULL;
1626 switch (u32Function)
1627 {
1628 case VBOX_SHCL_GUEST_FN_REPLY:
1629 /* Function does its own lookup. */
1630 break;
1631
1632 default:
1633 {
1634 pTransfer = ShClTransferCtxGetTransferById(&pClient->Transfers.Ctx, idTransfer);
1635 if (!pTransfer)
1636 {
1637 LogRel(("Shared Clipboard: Transfer with ID %RU16 not found\n", idTransfer));
1638 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
1639 }
1640 break;
1641 }
1642 }
1643
1644 if (RT_FAILURE(rc))
1645 return rc;
1646
1647 rc = VERR_INVALID_PARAMETER; /* Play safe. */
1648
1649 switch (u32Function)
1650 {
1651 case VBOX_SHCL_GUEST_FN_REPLY:
1652 {
1653 rc = shClSvcTransferHandleReply(pClient, idTransfer, cParms, aParms);
1654 break;
1655 }
1656
1657 case VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_READ:
1658 {
1659 if (cParms != VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ)
1660 break;
1661
1662 ASSERT_GUEST_RETURN(aParms[1].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE); /* Features */
1663 ASSERT_GUEST_RETURN(aParms[2].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE); /* # Entries */
1664
1665 SHCLLISTHDR rootListHdr;
1666 RT_ZERO(rootListHdr);
1667
1668 rootListHdr.cEntries = ShClTransferRootsCount(pTransfer);
1669 /** @todo BUGBUG What about the features? */
1670
1671 HGCMSvcSetU64(&aParms[0], 0 /* Context ID */);
1672 HGCMSvcSetU32(&aParms[1], rootListHdr.fFeatures);
1673 HGCMSvcSetU64(&aParms[2], rootListHdr.cEntries);
1674 break;
1675 }
1676
1677 case VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_WRITE:
1678 {
1679 SHCLLISTHDR lstHdr;
1680 rc = shClSvcTransferGetRootListHdr(cParms, aParms, &lstHdr);
1681 if (RT_SUCCESS(rc))
1682 {
1683 void *pvData = ShClTransferListHdrDup(&lstHdr);
1684 uint32_t cbData = sizeof(SHCLLISTHDR);
1685
1686 const PSHCLEVENT pEvent = ShClEventSourceGetFromId(&pClient->EventSrc, VBOX_SHCL_CONTEXTID_GET_EVENT(uCID));
1687 if (pEvent)
1688 {
1689 PSHCLEVENTPAYLOAD pPayload;
1690 rc = ShClPayloadAlloc(pEvent->idEvent, pvData, cbData, &pPayload);
1691 if (RT_SUCCESS(rc))
1692 {
1693 rc = ShClEventSignal(pEvent, pPayload);
1694 if (RT_FAILURE(rc))
1695 ShClPayloadFree(pPayload);
1696 }
1697 }
1698 else
1699 rc = VERR_SHCLPB_EVENT_ID_NOT_FOUND;
1700 }
1701 break;
1702 }
1703
1704 case VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_READ:
1705 {
1706 if (cParms != VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ)
1707 break;
1708
1709 ASSERT_GUEST_RETURN(aParms[1].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE); /* Info flags */
1710 ASSERT_GUEST_RETURN(aParms[2].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE); /* Entry index # */
1711 ASSERT_GUEST_RETURN(aParms[3].type == VBOX_HGCM_SVC_PARM_PTR, VERR_WRONG_PARAMETER_TYPE); /* Entry name */
1712 ASSERT_GUEST_RETURN(aParms[4].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE); /* Info size */
1713 ASSERT_GUEST_RETURN(aParms[5].type == VBOX_HGCM_SVC_PARM_PTR, VERR_WRONG_PARAMETER_TYPE); /* Info data */
1714
1715 uint32_t fInfo;
1716 rc = HGCMSvcGetU32(&aParms[1], &fInfo);
1717 AssertRCBreak(rc);
1718
1719 ASSERT_GUEST_RETURN(fInfo & VBOX_SHCL_INFO_F_FSOBJINFO, VERR_WRONG_PARAMETER_TYPE); /* Validate info flags. */
1720
1721 uint64_t uIdx;
1722 rc = HGCMSvcGetU64(&aParms[2], &uIdx);
1723 AssertRCBreak(rc);
1724
1725 PCSHCLLISTENTRY pEntry = ShClTransferRootsEntryGet(pTransfer, uIdx);
1726 if (pEntry)
1727 {
1728 /* Entry name */
1729 void *pvDst = aParms[3].u.pointer.addr;
1730 size_t cbDst = aParms[3].u.pointer.size;
1731 memcpy(pvDst, pEntry->pszName, RT_MIN(pEntry->cbName, cbDst));
1732
1733 /* Info size */
1734 HGCMSvcSetU32(&aParms[4], pEntry->cbInfo);
1735
1736 /* Info data */
1737 pvDst = aParms[5].u.pointer.addr;
1738 cbDst = aParms[5].u.pointer.size;
1739 memcpy(pvDst, pEntry->pvInfo, RT_MIN(pEntry->cbInfo, cbDst));
1740 }
1741 else
1742 rc = VERR_NOT_FOUND;
1743
1744 break;
1745 }
1746
1747 case VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_WRITE:
1748 {
1749 SHCLLISTENTRY lstEntry;
1750 rc = shClSvcTransferGetRootListEntry(cParms, aParms, &lstEntry);
1751 if (RT_SUCCESS(rc))
1752 {
1753 void *pvData = ShClTransferListEntryDup(&lstEntry);
1754 uint32_t cbData = sizeof(SHCLLISTENTRY);
1755
1756 const PSHCLEVENT pEvent = ShClEventSourceGetFromId(&pClient->EventSrc, VBOX_SHCL_CONTEXTID_GET_EVENT(uCID));
1757 if (pEvent)
1758 {
1759 PSHCLEVENTPAYLOAD pPayload;
1760 rc = ShClPayloadAlloc(pEvent->idEvent, pvData, cbData, &pPayload);
1761 if (RT_SUCCESS(rc))
1762 {
1763 rc = ShClEventSignal(pEvent, pPayload);
1764 if (RT_FAILURE(rc))
1765 ShClPayloadFree(pPayload);
1766 }
1767 }
1768 else
1769 rc = VERR_SHCLPB_EVENT_ID_NOT_FOUND;
1770 }
1771 break;
1772 }
1773
1774 case VBOX_SHCL_GUEST_FN_LIST_OPEN:
1775 {
1776 SHCLLISTOPENPARMS listOpenParms;
1777 rc = shClSvcTransferGetListOpen(cParms, aParms, &listOpenParms);
1778 if (RT_SUCCESS(rc))
1779 {
1780 SHCLLISTHANDLE hList;
1781 rc = ShClTransferListOpen(pTransfer, &listOpenParms, &hList);
1782 if (RT_SUCCESS(rc))
1783 {
1784 /* Return list handle. */
1785 HGCMSvcSetU64(&aParms[6], hList);
1786 }
1787 }
1788 break;
1789 }
1790
1791 case VBOX_SHCL_GUEST_FN_LIST_CLOSE:
1792 {
1793 if (cParms != VBOX_SHCL_CPARMS_LIST_CLOSE)
1794 break;
1795
1796 SHCLLISTHANDLE hList;
1797 rc = HGCMSvcGetU64(&aParms[1], &hList);
1798 if (RT_SUCCESS(rc))
1799 {
1800 rc = ShClTransferListClose(pTransfer, hList);
1801 }
1802 break;
1803 }
1804
1805 case VBOX_SHCL_GUEST_FN_LIST_HDR_READ:
1806 {
1807 if (cParms != VBOX_SHCL_CPARMS_LIST_HDR)
1808 break;
1809
1810 SHCLLISTHANDLE hList;
1811 rc = HGCMSvcGetU64(&aParms[1], &hList); /* Get list handle. */
1812 if (RT_SUCCESS(rc))
1813 {
1814 SHCLLISTHDR hdrList;
1815 rc = ShClTransferListGetHeader(pTransfer, hList, &hdrList);
1816 if (RT_SUCCESS(rc))
1817 rc = shClSvcTransferSetListHdr(cParms, aParms, &hdrList);
1818 }
1819 break;
1820 }
1821
1822 case VBOX_SHCL_GUEST_FN_LIST_HDR_WRITE:
1823 {
1824 SHCLLISTHDR hdrList;
1825 rc = ShClTransferListHdrInit(&hdrList);
1826 if (RT_SUCCESS(rc))
1827 {
1828 SHCLLISTHANDLE hList;
1829 rc = shClSvcTransferGetListHdr(cParms, aParms, &hList, &hdrList);
1830 if (RT_SUCCESS(rc))
1831 {
1832 void *pvData = ShClTransferListHdrDup(&hdrList);
1833 uint32_t cbData = sizeof(SHCLLISTHDR);
1834
1835 const PSHCLEVENT pEvent = ShClEventSourceGetFromId(&pClient->EventSrc, VBOX_SHCL_CONTEXTID_GET_EVENT(uCID));
1836 if (pEvent)
1837 {
1838 PSHCLEVENTPAYLOAD pPayload;
1839 rc = ShClPayloadAlloc(pEvent->idEvent, pvData, cbData, &pPayload);
1840 if (RT_SUCCESS(rc))
1841 {
1842 rc = ShClEventSignal(pEvent, pPayload);
1843 if (RT_FAILURE(rc))
1844 ShClPayloadFree(pPayload);
1845 }
1846 }
1847 else
1848 rc = VERR_SHCLPB_EVENT_ID_NOT_FOUND;
1849 }
1850 }
1851 break;
1852 }
1853
1854 case VBOX_SHCL_GUEST_FN_LIST_ENTRY_READ:
1855 {
1856 if (cParms != VBOX_SHCL_CPARMS_LIST_ENTRY)
1857 break;
1858
1859 SHCLLISTHANDLE hList;
1860 rc = HGCMSvcGetU64(&aParms[1], &hList); /* Get list handle. */
1861 if (RT_SUCCESS(rc))
1862 {
1863 SHCLLISTENTRY entryList;
1864 rc = ShClTransferListEntryInit(&entryList);
1865 if (RT_SUCCESS(rc))
1866 {
1867 rc = ShClTransferListRead(pTransfer, hList, &entryList);
1868 if (RT_SUCCESS(rc))
1869 rc = shClSvcTransferSetListEntry(cParms, aParms, &entryList);
1870 }
1871 }
1872 break;
1873 }
1874
1875 case VBOX_SHCL_GUEST_FN_LIST_ENTRY_WRITE:
1876 {
1877 SHCLLISTENTRY entryList;
1878 rc = ShClTransferListEntryInit(&entryList);
1879 if (RT_SUCCESS(rc))
1880 {
1881 SHCLLISTHANDLE hList;
1882 rc = shClSvcTransferGetListEntry(cParms, aParms, &hList, &entryList);
1883 if (RT_SUCCESS(rc))
1884 {
1885 void *pvData = ShClTransferListEntryDup(&entryList);
1886 uint32_t cbData = sizeof(SHCLLISTENTRY);
1887
1888 const PSHCLEVENT pEvent = ShClEventSourceGetFromId(&pClient->EventSrc, VBOX_SHCL_CONTEXTID_GET_EVENT(uCID));
1889 if (pEvent)
1890 {
1891 PSHCLEVENTPAYLOAD pPayload;
1892 rc = ShClPayloadAlloc(pEvent->idEvent, pvData, cbData, &pPayload);
1893 if (RT_SUCCESS(rc))
1894 {
1895 rc = ShClEventSignal(pEvent, pPayload);
1896 if (RT_FAILURE(rc))
1897 ShClPayloadFree(pPayload);
1898 }
1899 }
1900 else
1901 rc = VERR_SHCLPB_EVENT_ID_NOT_FOUND;
1902 }
1903 }
1904 break;
1905 }
1906
1907 case VBOX_SHCL_GUEST_FN_OBJ_OPEN:
1908 {
1909 ASSERT_GUEST_STMT_BREAK(cParms == VBOX_SHCL_CPARMS_OBJ_OPEN, VERR_WRONG_PARAMETER_COUNT);
1910
1911 SHCLOBJOPENCREATEPARMS openCreateParms;
1912 RT_ZERO(openCreateParms);
1913
1914 /* aParms[1] will return the object handle on success; see below. */
1915 rc = HGCMSvcGetStr(&aParms[2], &openCreateParms.pszPath, &openCreateParms.cbPath);
1916 if (RT_SUCCESS(rc))
1917 rc = HGCMSvcGetU32(&aParms[3], &openCreateParms.fCreate);
1918
1919 if (RT_SUCCESS(rc))
1920 {
1921 SHCLOBJHANDLE hObj;
1922 rc = ShClTransferObjOpen(pTransfer, &openCreateParms, &hObj);
1923 if (RT_SUCCESS(rc))
1924 {
1925 LogFlowFunc(("hObj=%RU64\n", hObj));
1926
1927 HGCMSvcSetU64(&aParms[1], hObj);
1928 }
1929 }
1930 break;
1931 }
1932
1933 case VBOX_SHCL_GUEST_FN_OBJ_CLOSE:
1934 {
1935 if (cParms != VBOX_SHCL_CPARMS_OBJ_CLOSE)
1936 break;
1937
1938 SHCLOBJHANDLE hObj;
1939 rc = HGCMSvcGetU64(&aParms[1], &hObj); /* Get object handle. */
1940 if (RT_SUCCESS(rc))
1941 rc = ShClTransferObjClose(pTransfer, hObj);
1942 break;
1943 }
1944
1945 case VBOX_SHCL_GUEST_FN_OBJ_READ:
1946 {
1947 if (cParms != VBOX_SHCL_CPARMS_OBJ_READ)
1948 break;
1949
1950 ASSERT_GUEST_RETURN(aParms[1].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE); /* Object handle */
1951 ASSERT_GUEST_RETURN(aParms[2].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE); /* Bytes to read */
1952 ASSERT_GUEST_RETURN(aParms[3].type == VBOX_HGCM_SVC_PARM_PTR, VERR_WRONG_PARAMETER_TYPE); /* Data buffer */
1953 ASSERT_GUEST_RETURN(aParms[4].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE); /* Checksum data size */
1954 ASSERT_GUEST_RETURN(aParms[5].type == VBOX_HGCM_SVC_PARM_PTR, VERR_WRONG_PARAMETER_TYPE); /* Checksum data buffer*/
1955
1956 SHCLOBJHANDLE hObj;
1957 rc = HGCMSvcGetU64(&aParms[1], &hObj); /* Get object handle. */
1958 AssertRCBreak(rc);
1959
1960 uint32_t cbToRead = 0;
1961 rc = HGCMSvcGetU32(&aParms[2], &cbToRead);
1962 AssertRCBreak(rc);
1963
1964 void *pvBuf = NULL;
1965 uint32_t cbBuf = 0;
1966 rc = HGCMSvcGetPv(&aParms[3], &pvBuf, &cbBuf);
1967 AssertRCBreak(rc);
1968
1969 LogFlowFunc(("hObj=%RU64, cbBuf=%RU32, cbToRead=%RU32, rc=%Rrc\n", hObj, cbBuf, cbToRead, rc));
1970
1971 if ( RT_SUCCESS(rc)
1972 && ( !cbBuf
1973 || !cbToRead
1974 || cbBuf < cbToRead
1975 )
1976 )
1977 {
1978 rc = VERR_INVALID_PARAMETER;
1979 }
1980
1981 if (RT_SUCCESS(rc))
1982 {
1983 uint32_t cbRead;
1984 rc = ShClTransferObjRead(pTransfer, hObj, pvBuf, cbToRead, 0 /* fFlags */, &cbRead);
1985 if (RT_SUCCESS(rc))
1986 {
1987 HGCMSvcSetU32(&aParms[2], cbRead);
1988
1989 /** @todo Implement checksum support. */
1990 }
1991 }
1992 break;
1993 }
1994
1995 case VBOX_SHCL_GUEST_FN_OBJ_WRITE:
1996 {
1997 SHCLOBJDATACHUNK dataChunk;
1998
1999 rc = shClSvcTransferGetObjDataChunk(cParms, aParms, &dataChunk);
2000 if (RT_SUCCESS(rc))
2001 {
2002 void *pvData = ShClTransferObjDataChunkDup(&dataChunk);
2003 uint32_t cbData = sizeof(SHCLOBJDATACHUNK);
2004
2005 const PSHCLEVENT pEvent = ShClEventSourceGetFromId(&pClient->EventSrc, VBOX_SHCL_CONTEXTID_GET_EVENT(uCID));
2006 if (pEvent)
2007 {
2008 PSHCLEVENTPAYLOAD pPayload;
2009 rc = ShClPayloadAlloc(pEvent->idEvent, pvData, cbData, &pPayload);
2010 if (RT_SUCCESS(rc))
2011 {
2012 rc = ShClEventSignal(pEvent, pPayload);
2013 if (RT_FAILURE(rc))
2014 ShClPayloadFree(pPayload);
2015 }
2016 }
2017 else
2018 rc = VERR_SHCLPB_EVENT_ID_NOT_FOUND;
2019 }
2020
2021 break;
2022 }
2023
2024 default:
2025 rc = VERR_NOT_IMPLEMENTED;
2026 break;
2027 }
2028
2029 /* If anything wrong has happened, make sure to unregister the transfer again (if not done already) and tell the guest. */
2030 if ( RT_FAILURE(rc)
2031 && pTransfer)
2032 {
2033 shClSvcClientLock(pClient);
2034
2035 /* Let the guest know. */
2036 int rc2 = shClSvcTransferSendStatusAsyncInternal(pClient, pTransfer,
2037 SHCLTRANSFERSTATUS_ERROR, rc, NULL /* ppEvent */);
2038 AssertRC(rc2);
2039
2040 ShClSvcTransferDestroy(pClient, pTransfer);
2041
2042 shClSvcClientUnlock(pClient);
2043 }
2044
2045 LogFlowFunc(("[Client %RU32] Returning rc=%Rrc\n", pClient->State.uClientID, rc));
2046 return rc;
2047}
2048
2049/**
2050 * Transfer host handler for the Shared Clipboard host service.
2051 *
2052 * @returns VBox status code.
2053 * @param u32Function Function number being called.
2054 * @param cParms Number of function parameters supplied.
2055 * @param aParms Array function parameters supplied.
2056 */
2057int shClSvcTransferHostHandler(uint32_t u32Function,
2058 uint32_t cParms,
2059 VBOXHGCMSVCPARM aParms[])
2060{
2061 RT_NOREF(cParms, aParms);
2062
2063 int rc = VERR_NOT_IMPLEMENTED; /* Play safe. */
2064
2065 switch (u32Function)
2066 {
2067 case VBOX_SHCL_HOST_FN_CANCEL: /** @todo BUGBUG Implement this. */
2068 break;
2069
2070 case VBOX_SHCL_HOST_FN_ERROR: /** @todo BUGBUG Implement this. */
2071 break;
2072
2073 default:
2074 break;
2075
2076 }
2077
2078 LogFlowFuncLeaveRC(rc);
2079 return rc;
2080}
2081
2082int shClSvcTransferHostMsgHandler(PSHCLCLIENT pClient, PSHCLCLIENTMSG pMsg)
2083{
2084 RT_NOREF(pClient);
2085
2086 int rc;
2087
2088 switch (pMsg->idMsg)
2089 {
2090 default:
2091 rc = VINF_SUCCESS;
2092 break;
2093 }
2094
2095 LogFlowFuncLeaveRC(rc);
2096 return rc;
2097}
2098
2099/**
2100 * Reports a transfer status to the guest.
2101 *
2102 * @returns VBox status code.
2103 * @param pClient Client that owns the transfer.
2104 * @param idTransfer Transfer ID to report status for.
2105 * @param enmDir Transfer direction to report status for.
2106 * @param uStatus Status to report.
2107 * @param rcTransfer Result code to report. Optional and depending on status.
2108 * @param ppEvent Where to return the wait event on success. Optional.
2109 * Must be released by the caller with ShClEventRelease().
2110 *
2111 * @note Caller must enter the client's critical section.
2112 */
2113static int shClSvcTransferSendStatusExAsync(PSHCLCLIENT pClient, SHCLTRANSFERID idTransfer, SHCLTRANSFERDIR enmDir, SHCLTRANSFERSTATUS uStatus,
2114 int rcTransfer, PSHCLEVENT *ppEvent)
2115{
2116 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
2117 AssertReturn(idTransfer != NIL_SHCLTRANSFERID, VERR_INVALID_PARAMETER);
2118 /* ppEvent is optional. */
2119
2120 PSHCLCLIENTMSG pMsgReadData = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_STATUS,
2121 VBOX_SHCL_CPARMS_TRANSFER_STATUS);
2122 if (!pMsgReadData)
2123 return VERR_NO_MEMORY;
2124
2125 PSHCLEVENT pEvent;
2126 int rc = ShClEventSourceGenerateAndRegisterEvent(&pClient->EventSrc, &pEvent);
2127 if (RT_SUCCESS(rc))
2128 {
2129 HGCMSvcSetU64(&pMsgReadData->aParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID, idTransfer, pEvent->idEvent));
2130 HGCMSvcSetU32(&pMsgReadData->aParms[1], enmDir);
2131 HGCMSvcSetU32(&pMsgReadData->aParms[2], uStatus);
2132 HGCMSvcSetU32(&pMsgReadData->aParms[3], (uint32_t)rcTransfer); /** @todo uint32_t vs. int. */
2133 HGCMSvcSetU32(&pMsgReadData->aParms[4], 0 /* fFlags, unused */);
2134
2135 shClSvcMsgAdd(pClient, pMsgReadData, true /* fAppend */);
2136
2137 rc = shClSvcClientWakeup(pClient);
2138 if (RT_SUCCESS(rc))
2139 {
2140 LogRel2(("Shared Clipboard: Reported status %s (rc=%Rrc) of transfer %RU32 to guest\n",
2141 ShClTransferStatusToStr(uStatus), rcTransfer, idTransfer));
2142
2143 if (ppEvent)
2144 {
2145 *ppEvent = pEvent; /* Takes ownership. */
2146 }
2147 else /* If event is not consumed by the caller, release the event again. */
2148 ShClEventRelease(pEvent);
2149 }
2150 else
2151 ShClEventRelease(pEvent);
2152 }
2153 else
2154 rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
2155
2156 if (RT_FAILURE(rc))
2157 LogRel(("Shared Clipboard: Reporting status %s (%Rrc) for transfer %RU32 to guest failed with %Rrc\n",
2158 ShClTransferStatusToStr(uStatus), rcTransfer, idTransfer, rc));
2159
2160 LogFlowFuncLeaveRC(rc);
2161 return rc;
2162}
2163
2164/**
2165 * Reports a transfer status to the guest.
2166 *
2167 * @returns VBox status code.
2168 * @param pClient Client that owns the transfer.
2169 * @param pTransfer Transfer to report status for.
2170 * @param uStatus Status to report.
2171 * @param rcTransfer Result code to report. Optional and depending on status.
2172 * @param ppEvent Where to return the wait event on success. Optional.
2173 * Must be released by the caller with ShClEventRelease().
2174 *
2175 * @note Caller must enter the client's critical section.
2176 */
2177static int shClSvcTransferSendStatusAsyncInternal(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, SHCLTRANSFERSTATUS uStatus,
2178 int rcTransfer, PSHCLEVENT *ppEvent)
2179{
2180 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
2181 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2182 /* ppEvent is optional. */
2183
2184 return shClSvcTransferSendStatusExAsync(pClient, ShClTransferGetID(pTransfer), ShClTransferGetDir(pTransfer),
2185 uStatus, rcTransfer, ppEvent);
2186}
2187
2188int ShClSvcTransferSendStatusAsync(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, SHCLTRANSFERSTATUS uStatus,
2189 int rcTransfer, PSHCLEVENT *ppEvent)
2190{
2191 shClSvcClientLock(pClient);
2192
2193 int rc = shClSvcTransferSendStatusAsyncInternal(pClient, pTransfer, uStatus, rcTransfer, ppEvent);
2194
2195 shClSvcClientUnlock(pClient);
2196
2197 return rc;
2198}
2199
2200/**
2201 * Cleans up (unregisters and destroys) all transfers not in started state (anymore).
2202 *
2203 * @param pClient Client to clean up transfers for.
2204 *
2205 * @note Caller needs to take the critical section.
2206 */
2207static void shClSvcTransferCleanupAllUnused(PSHCLCLIENT pClient)
2208{
2209 Assert(RTCritSectIsOwner(&pClient->CritSect));
2210
2211 LogFlowFuncEnter();
2212
2213 PSHCLTRANSFERCTX pTxCtx = &pClient->Transfers.Ctx;
2214
2215 PSHCLTRANSFER pTransfer, pTransferNext;
2216 RTListForEachSafe(&pTxCtx->List, pTransfer, pTransferNext, SHCLTRANSFER, Node)
2217 {
2218 SHCLTRANSFERSTATUS const enmSts = ShClTransferGetStatus(pTransfer);
2219 if (enmSts != SHCLTRANSFERSTATUS_STARTED)
2220 {
2221 /* Let the guest know. */
2222 int rc2 = shClSvcTransferSendStatusAsyncInternal(pClient, pTransfer,
2223 SHCLTRANSFERSTATUS_UNINITIALIZED, VINF_SUCCESS, NULL /* ppEvent */);
2224 AssertRC(rc2);
2225
2226 ShClTransferCtxUnregisterById(pTxCtx, pTransfer->State.uID);
2227
2228 ShClTransferDestroy(pTransfer);
2229
2230 RTMemFree(pTransfer);
2231 pTransfer = NULL;
2232 }
2233 }
2234}
2235
2236/**
2237 * Creates a new transfer on the host.
2238 *
2239 * @returns VBox status code.
2240 * @param pClient Client that owns the transfer.
2241 * @param enmDir Transfer direction to create.
2242 * @param enmSource Transfer source to create.
2243 * @param idTransfer Transfer ID to use for creation.
2244 * If set to NIL_SHCLTRANSFERID, a new transfer ID will be created.
2245 * @param ppTransfer Where to return the created transfer on success. Optional and can be NULL.
2246 */
2247int ShClSvcTransferCreate(PSHCLCLIENT pClient, SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource, SHCLTRANSFERID idTransfer, PSHCLTRANSFER *ppTransfer)
2248{
2249 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
2250 /* ppTransfer is optional. */
2251
2252 LogFlowFuncEnter();
2253
2254 shClSvcClientLock(pClient);
2255
2256 /* When creating a new transfer, this is a good time to clean up old stuff we don't need anymore. */
2257 shClSvcTransferCleanupAllUnused(pClient);
2258
2259 PSHCLTRANSFER pTransfer;
2260 int rc = ShClTransferCreate(enmDir, enmSource, &pTransfer);
2261 if (RT_SUCCESS(rc))
2262 {
2263 if (idTransfer == NIL_SHCLTRANSFERID)
2264 rc = ShClTransferCtxRegister(&pClient->Transfers.Ctx, pTransfer, &idTransfer);
2265 else
2266 rc = ShClTransferCtxRegisterById(&pClient->Transfers.Ctx, pTransfer, idTransfer);
2267 if (RT_SUCCESS(rc))
2268 {
2269 if (ppTransfer)
2270 *ppTransfer = pTransfer;
2271 }
2272 }
2273
2274 shClSvcClientUnlock(pClient);
2275
2276 if (RT_FAILURE(rc))
2277 {
2278 ShClTransferDestroy(pTransfer);
2279
2280 RTMemFree(pTransfer);
2281 pTransfer = NULL;
2282 }
2283
2284 if (RT_FAILURE(rc))
2285 LogRel(("Shared Clipboard: Creating transfer failed with %Rrc\n", rc));
2286
2287 LogFlowFuncLeaveRC(rc);
2288 return rc;
2289}
2290
2291/**
2292 * Destroys a transfer on the host.
2293 *
2294 * @param pClient Client to destroy transfer for.
2295 * @param pTransfer Transfer to destroy.
2296 * The pointer will be invalid after return.
2297 */
2298void ShClSvcTransferDestroy(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
2299{
2300 if (!pTransfer)
2301 return;
2302
2303 LogFlowFuncEnter();
2304
2305 PSHCLTRANSFERCTX pTxCtx = &pClient->Transfers.Ctx;
2306
2307 ShClTransferCtxUnregisterById(pTxCtx, pTransfer->State.uID);
2308
2309 ShClTransferDestroy(pTransfer);
2310
2311 RTMemFree(pTransfer);
2312 pTransfer = NULL;
2313
2314 LogFlowFuncLeave();
2315}
2316
2317/**
2318 * Initializes a (created) transfer on the host.
2319 *
2320 * @returns VBox status code.
2321 * @param pClient Client that owns the transfer.
2322 * @param pTransfer Transfer to initialize.
2323 */
2324int ShClSvcTransferInit(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
2325{
2326 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
2327
2328 LogFlowFuncEnter();
2329
2330 shClSvcClientLock(pClient);
2331
2332 Assert(ShClTransferGetStatus(pTransfer) == SHCLTRANSFERSTATUS_NONE);
2333
2334 PSHCLTRANSFERCTX pTxCtx = &pClient->Transfers.Ctx;
2335
2336 int rc;
2337
2338 if (!ShClTransferCtxIsMaximumReached(pTxCtx))
2339 {
2340 SHCLTRANSFERDIR const enmDir = ShClTransferGetDir(pTransfer);
2341
2342 LogRel2(("Shared Clipboard: Initializing %s transfer ...\n",
2343 enmDir == SHCLTRANSFERDIR_FROM_REMOTE ? "guest -> host" : "host -> guest"));
2344
2345 SHCLTXPROVIDER Provider;
2346 RT_ZERO(Provider);
2347
2348 /* Assign local provider first and overwrite interface methods below if needed. */
2349 ShClTransferProviderLocalQueryInterface(&Provider);
2350
2351 if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE) /* Guest -> Host. */
2352 {
2353 Provider.Interface.pfnRootListRead = shClSvcTransferIfaceGHRootListRead;
2354
2355 Provider.Interface.pfnListOpen = shClSvcTransferIfaceGHListOpen;
2356 Provider.Interface.pfnListClose = shClSvcTransferIfaceGHListClose;
2357 Provider.Interface.pfnListHdrRead = shClSvcTransferIfaceGHListHdrRead;
2358 Provider.Interface.pfnListEntryRead = shClSvcTransferIfaceGHListEntryRead;
2359
2360 Provider.Interface.pfnObjOpen = shClSvcTransferIfaceGHObjOpen;
2361 Provider.Interface.pfnObjClose = shClSvcTransferIfaceGHObjClose;
2362 Provider.Interface.pfnObjRead = shClSvcTransferIfaceGHObjRead;
2363 }
2364 else if (enmDir == SHCLTRANSFERDIR_TO_REMOTE) /* Host -> Guest. */
2365 {
2366 Provider.Interface.pfnListHdrWrite = shClSvcTransferIfaceHGListHdrWrite;
2367 Provider.Interface.pfnListEntryWrite = shClSvcTransferIfaceHGListEntryWrite;
2368 Provider.Interface.pfnObjWrite = shClSvcTransferIfaceHGObjWrite;
2369 }
2370 else
2371 AssertFailed();
2372
2373 Provider.enmSource = pClient->State.enmSource;
2374 Provider.pvUser = pClient;
2375
2376 rc = ShClTransferSetProvider(pTransfer, &Provider);
2377 if (RT_SUCCESS(rc))
2378 {
2379 ShClTransferSetCallbacks(pTransfer, &pClient->Transfers.Callbacks);
2380
2381 rc = ShClTransferInit(pTransfer);
2382 if (RT_SUCCESS(rc))
2383 {
2384 /* Sanity: Make sure that the transfer we're gonna report as INITIALIZED to the guest
2385 * actually has some root entries set, as the guest can query for those at any time then. */
2386 if (enmDir == SHCLTRANSFERDIR_TO_REMOTE)
2387 AssertMsgStmt(ShClTransferRootsCount(pTransfer), ("Transfer has no root entries set\n"), rc = VERR_WRONG_ORDER);
2388 }
2389 }
2390 }
2391 else
2392 rc = VERR_SHCLPB_MAX_TRANSFERS_REACHED;
2393
2394 /* Tell the guest the outcome. */
2395 int rc2 = shClSvcTransferSendStatusAsyncInternal(pClient, pTransfer,
2396 RT_SUCCESS(rc)
2397 ? SHCLTRANSFERSTATUS_INITIALIZED : SHCLTRANSFERSTATUS_ERROR, rc,
2398 NULL /* ppEvent */);
2399 if (RT_SUCCESS(rc))
2400 rc2 = rc;
2401
2402 if (RT_FAILURE(rc))
2403 LogRel(("Shared Clipboard: Initializing transfer failed with %Rrc\n", rc));
2404
2405 shClSvcClientUnlock(pClient);
2406
2407 LogFlowFuncLeaveRC(rc);
2408 return rc;
2409}
2410
2411/**
2412 * Starts a transfer, communicating the status to the guest side.
2413 *
2414 * @returns VBox status code.
2415 * @param pClient Client that owns the transfer.
2416 * @param pTransfer Transfer to start.
2417 */
2418int ShClSvcTransferStart(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
2419{
2420 LogRel2(("Shared Clipboard: Starting transfer %RU32 ...\n", pTransfer->State.uID));
2421
2422 shClSvcClientLock(pClient);
2423
2424 int rc = ShClTransferStart(pTransfer);
2425
2426 /* Let the guest know in any case
2427 * (so that it can tear down the transfer on error as well). */
2428 int rc2 = shClSvcTransferSendStatusAsyncInternal(pClient, pTransfer,
2429 RT_SUCCESS(rc) ? SHCLTRANSFERSTATUS_STARTED : SHCLTRANSFERSTATUS_ERROR, rc,
2430 NULL /* ppEvent */);
2431 if (RT_SUCCESS(rc))
2432 rc = rc2;
2433
2434 shClSvcClientUnlock(pClient);
2435 return rc;
2436}
2437
2438/**
2439 * Stops (and destroys) a transfer, communicating the status to the guest side.
2440 *
2441 * @returns VBox status code.
2442 * @param pClient Client that owns the transfer.
2443 * @param pTransfer Transfer to stop. The pointer will be invalid on success.
2444 * @param fWaitForGuest Set to \c true to wait for acknowledgement from guest, or \c false to skip waiting.
2445 */
2446int ShClSvcTransferStop(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, bool fWaitForGuest)
2447{
2448 LogRel2(("Shared Clipboard: Stopping transfer %RU32 ...\n", pTransfer->State.uID));
2449
2450 shClSvcClientLock(pClient);
2451
2452 PSHCLEVENT pEvent;
2453 int rc = shClSvcTransferSendStatusAsyncInternal(pClient, pTransfer,
2454 SHCLTRANSFERSTATUS_STOPPED, VINF_SUCCESS, &pEvent);
2455 if ( RT_SUCCESS(rc)
2456 && fWaitForGuest)
2457 {
2458 LogRel2(("Shared Clipboard: Waiting for stop of transfer %RU32 on guest ...\n", pTransfer->State.uID));
2459
2460 shClSvcClientUnlock(pClient);
2461
2462 rc = ShClEventWait(pEvent, pTransfer->uTimeoutMs, NULL /* ppPayload */);
2463 if (RT_SUCCESS(rc))
2464 LogRel2(("Shared Clipboard: Stopped transfer %RU32 on guest\n", pTransfer->State.uID));
2465
2466 ShClEventRelease(pEvent);
2467
2468 shClSvcClientLock(pClient);
2469 }
2470
2471 if (RT_FAILURE(rc))
2472 LogRel(("Shared Clipboard: Unable to stop transfer %RU32 on guest, rc=%Rrc\n",
2473 pTransfer->State.uID, rc));
2474
2475 shClSvcClientUnlock(pClient);
2476
2477 LogFlowFuncLeaveRC(rc);
2478 return rc;
2479}
2480
2481/**
2482 * Sets the host service's (file) transfer mode.
2483 *
2484 * @returns VBox status code.
2485 * @param fMode Transfer mode to set.
2486 */
2487int shClSvcTransferModeSet(uint32_t fMode)
2488{
2489 if (fMode & ~VBOX_SHCL_TRANSFER_MODE_F_VALID_MASK)
2490 return VERR_INVALID_FLAGS;
2491
2492 g_fTransferMode = fMode;
2493
2494 LogRel2(("Shared Clipboard: File transfers are now %s\n",
2495 g_fTransferMode & VBOX_SHCL_TRANSFER_MODE_F_ENABLED ? "enabled" : "disabled"));
2496
2497 /* If file transfers are being disabled, make sure to also reset (destroy) all pending transfers. */
2498 if (!(g_fTransferMode & VBOX_SHCL_TRANSFER_MODE_F_ENABLED))
2499 {
2500 ClipboardClientMap::const_iterator itClient = g_mapClients.begin();
2501 while (itClient != g_mapClients.end())
2502 {
2503 PSHCLCLIENT pClient = itClient->second;
2504 AssertPtr(pClient);
2505
2506 shClSvcTransferDestroyAll(pClient);
2507
2508 ++itClient;
2509 }
2510 }
2511
2512 LogFlowFuncLeaveRC(VINF_SUCCESS);
2513 return VINF_SUCCESS;
2514}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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