VirtualBox

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

Last change on this file since 86949 was 86949, checked in by vboxsync, 4 years ago

Shared Clipboard/Transfers: Transfer IDs are 32-bit and of type SHCLTRANSFERID. bugref:9437

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