VirtualBox

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

Last change on this file since 82847 was 82847, checked in by vboxsync, 5 years ago

Shared Clipboard: Renaming, to get the transfer code compiled again. bugref:9437

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