VirtualBox

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

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

Shared Clipboard/Transfers: Logging nit.

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