VirtualBox

source: vbox/trunk/src/VBox/HostServices/DragAndDrop/service.cpp@ 58257

Last change on this file since 58257 was 58257, checked in by vboxsync, 9 years ago

DnD: Added context IDs for all HGCM messages.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.8 KB
Line 
1/* $Id: service.cpp 58257 2015-10-15 08:31:46Z vboxsync $ */
2/** @file
3 * Drag and Drop Service.
4 */
5
6/*
7 * Copyright (C) 2011-2015 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/** @page pg_svc_guest_control Drag and drop HGCM Service
19 *
20 * TODO
21 */
22
23
24/*********************************************************************************************************************************
25* Header Files *
26*********************************************************************************************************************************/
27#ifdef LOG_GROUP
28 #undef LOG_GROUP
29#endif
30#define LOG_GROUP LOG_GROUP_GUEST_DND
31
32#include <map>
33
34#include <VBox/GuestHost/DragAndDrop.h>
35#include <VBox/HostServices/Service.h>
36#include <VBox/HostServices/DragAndDropSvc.h>
37
38#include "dndmanager.h"
39
40using namespace DragAndDropSvc;
41
42/*********************************************************************************************************************************
43* Service class declaration *
44*********************************************************************************************************************************/
45
46/** Map holding pointers to HGCM clients. Key is the (unique) HGCM client ID. */
47typedef std::map<uint32_t, HGCM::Client*> DnDClientMap;
48
49/**
50 * Specialized drag & drop service class.
51 */
52class DragAndDropService : public HGCM::AbstractService<DragAndDropService>
53{
54public:
55
56 explicit DragAndDropService(PVBOXHGCMSVCHELPERS pHelpers)
57 : HGCM::AbstractService<DragAndDropService>(pHelpers)
58 , m_pManager(NULL) {}
59
60protected:
61
62 int init(VBOXHGCMSVCFNTABLE *pTable);
63 int uninit(void);
64 int clientConnect(uint32_t u32ClientID, void *pvClient);
65 int clientDisconnect(uint32_t u32ClientID, void *pvClient);
66 void guestCall(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, void *pvClient, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
67 int hostCall(uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
68
69 int modeSet(uint32_t u32Mode);
70 inline uint32_t modeGet() { return m_u32Mode; };
71
72protected:
73
74 static DECLCALLBACK(int) progressCallback(uint32_t uStatus, uint32_t uPercentage, int rc, void *pvUser);
75
76protected:
77
78 DnDManager *m_pManager;
79 /** Map of all connected clients. */
80 DnDClientMap m_clientMap;
81 /** List of all clients which are queued up (deferred return) and ready
82 * to process new commands. */
83 RTCList<HGCM::Client*> m_clientQueue;
84 uint32_t m_u32Mode;
85};
86
87
88/*********************************************************************************************************************************
89* Service class implementation *
90*********************************************************************************************************************************/
91
92int DragAndDropService::init(VBOXHGCMSVCFNTABLE *pTable)
93{
94 /* Register functions. */
95 pTable->pfnHostCall = svcHostCall;
96 pTable->pfnSaveState = NULL; /* The service is stateless, so the normal */
97 pTable->pfnLoadState = NULL; /* construction done before restoring suffices */
98 pTable->pfnRegisterExtension = svcRegisterExtension;
99
100 /* Drag'n drop mode is disabled by default. */
101 modeSet(VBOX_DRAG_AND_DROP_MODE_OFF);
102
103 int rc = VINF_SUCCESS;
104
105 try
106 {
107 m_pManager = new DnDManager(&DragAndDropService::progressCallback, this);
108 }
109 catch(std::bad_alloc &)
110 {
111 rc = VERR_NO_MEMORY;
112 }
113
114 LogFlowFuncLeaveRC(rc);
115 return rc;
116}
117
118int DragAndDropService::uninit(void)
119{
120 if (m_pManager)
121 {
122 delete m_pManager;
123 m_pManager = NULL;
124 }
125
126 return VINF_SUCCESS;
127}
128
129int DragAndDropService::clientConnect(uint32_t u32ClientID, void *pvClient)
130{
131 if (m_clientMap.size() >= UINT8_MAX) /* Don't allow too much clients at the same time. */
132 {
133 AssertMsgFailed(("Maximum number of clients reached\n"));
134 return VERR_MAX_PROCS_REACHED;
135 }
136
137 int rc = VINF_SUCCESS;
138
139 /*
140 * Add client to our client map.
141 */
142 if (m_clientMap.find(u32ClientID) != m_clientMap.end())
143 rc = VERR_ALREADY_EXISTS;
144
145 if (RT_SUCCESS(rc))
146 {
147 try
148 {
149 m_clientMap[u32ClientID] = new HGCM::Client(u32ClientID);
150 }
151 catch(std::bad_alloc &)
152 {
153 rc = VERR_NO_MEMORY;
154 }
155
156 if (RT_SUCCESS(rc))
157 {
158 /*
159 * Clear the message queue as soon as a new clients connect
160 * to ensure that every client has the same state.
161 */
162 if (m_pManager)
163 m_pManager->clear();
164 }
165 }
166
167 LogFlowFunc(("Client %RU32 connected, rc=%Rrc\n", u32ClientID, rc));
168 return rc;
169}
170
171int DragAndDropService::clientDisconnect(uint32_t u32ClientID, void *pvClient)
172{
173 /* Client not found? Bail out early. */
174 DnDClientMap::iterator itClient = m_clientMap.find(u32ClientID);
175 if (itClient == m_clientMap.end())
176 return VERR_NOT_FOUND;
177
178 /*
179 * Remove from waiters queue.
180 */
181 for (size_t i = 0; i < m_clientQueue.size(); i++)
182 {
183 HGCM::Client *pClient = m_clientQueue.at(i);
184 if (pClient->clientId() == u32ClientID)
185 {
186 if (m_pHelpers)
187 m_pHelpers->pfnCallComplete(pClient->handle(), VERR_INTERRUPTED);
188
189 m_clientQueue.removeAt(i);
190 delete pClient;
191
192 break;
193 }
194 }
195
196 /*
197 * Remove from client map and deallocate.
198 */
199 AssertPtr(itClient->second);
200 delete itClient->second;
201
202 m_clientMap.erase(itClient);
203
204 LogFlowFunc(("Client %RU32 disconnected\n", u32ClientID));
205 return VINF_SUCCESS;
206}
207
208int DragAndDropService::modeSet(uint32_t u32Mode)
209{
210 /** @todo Validate mode. */
211 switch (u32Mode)
212 {
213 case VBOX_DRAG_AND_DROP_MODE_OFF:
214 case VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST:
215 case VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST:
216 case VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL:
217 m_u32Mode = u32Mode;
218 break;
219
220 default:
221 m_u32Mode = VBOX_DRAG_AND_DROP_MODE_OFF;
222 break;
223 }
224
225 return VINF_SUCCESS;
226}
227
228void DragAndDropService::guestCall(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID,
229 void *pvClient, uint32_t u32Function,
230 uint32_t cParms, VBOXHGCMSVCPARM paParms[])
231{
232 LogFlowFunc(("u32ClientID=%RU32, u32Function=%RU32, cParms=%RU32\n",
233 u32ClientID, u32Function, cParms));
234
235 /* Check if we've the right mode set. */
236 int rc = VERR_ACCESS_DENIED; /* Play safe. */
237 switch (u32Function)
238 {
239 case GUEST_DND_GET_NEXT_HOST_MSG:
240 {
241 if (modeGet() != VBOX_DRAG_AND_DROP_MODE_OFF)
242 {
243 rc = VINF_SUCCESS;
244 }
245 else
246 {
247 LogFlowFunc(("DnD disabled, deferring request\n"));
248 rc = VINF_HGCM_ASYNC_EXECUTE;
249 }
250 break;
251 }
252
253 /* New since protocol v2. */
254 case GUEST_DND_CONNECT:
255 {
256 /*
257 * Never block the initial connect call, as the clients do this when
258 * initializing and might get stuck if drag and drop is set to "disabled" at
259 * that time.
260 */
261 rc = VINF_SUCCESS;
262 break;
263 }
264 case GUEST_DND_HG_ACK_OP:
265 /* Fall through is intentional. */
266 case GUEST_DND_HG_REQ_DATA:
267 /* Fall through is intentional. */
268 case GUEST_DND_HG_EVT_PROGRESS:
269 {
270 if ( modeGet() == VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
271 || modeGet() == VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST)
272 {
273 rc = VINF_SUCCESS;
274 }
275 else
276 LogFlowFunc(("Host -> Guest DnD mode disabled, ignoring request\n"));
277 break;
278 }
279
280 case GUEST_DND_GH_ACK_PENDING:
281 case GUEST_DND_GH_SND_DATA_HDR:
282 case GUEST_DND_GH_SND_DATA:
283 case GUEST_DND_GH_SND_DIR:
284 case GUEST_DND_GH_SND_FILE_HDR:
285 case GUEST_DND_GH_SND_FILE_DATA:
286 case GUEST_DND_GH_EVT_ERROR:
287 {
288#ifdef VBOX_WITH_DRAG_AND_DROP_GH
289 if ( modeGet() == VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
290 || modeGet() == VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST)
291 {
292 rc = VINF_SUCCESS;
293 }
294 else
295#endif
296 LogFlowFunc(("Guest -> Host DnD mode disabled, ignoring request\n"));
297 break;
298 }
299
300 default:
301 /* Reach through to DnD manager. */
302 rc = VINF_SUCCESS;
303 break;
304 }
305
306#ifdef DEBUG_andy
307 LogFlowFunc(("Mode (%RU32) check rc=%Rrc\n", modeGet(), rc));
308#endif
309
310#define DO_HOST_CALLBACK(); \
311 if ( RT_SUCCESS(rc) \
312 && m_pfnHostCallback) \
313 { \
314 rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data)); \
315 }
316
317 if (rc == VINF_SUCCESS) /* Note: rc might be VINF_HGCM_ASYNC_EXECUTE! */
318 {
319 DnDClientMap::iterator itClient = m_clientMap.find(u32ClientID);
320 Assert(itClient != m_clientMap.end());
321
322 HGCM::Client *pClient = itClient->second;
323 AssertPtr(pClient);
324
325 LogFlowFunc(("Client %RU32: Protocol v%RU32\n", pClient->clientId(), pClient->protocol()));
326
327 rc = VERR_INVALID_PARAMETER; /* Play safe. */
328
329 switch (u32Function)
330 {
331 /*
332 * Note: Older VBox versions with enabled DnD guest->host support (< 5.0)
333 * used the same message ID (300) for GUEST_DND_GET_NEXT_HOST_MSG and
334 * HOST_DND_GH_REQ_PENDING, which led this service returning
335 * VERR_INVALID_PARAMETER when the guest wanted to actually
336 * handle HOST_DND_GH_REQ_PENDING.
337 */
338 case GUEST_DND_GET_NEXT_HOST_MSG:
339 {
340 LogFlowFunc(("GUEST_DND_GET_NEXT_HOST_MSG\n"));
341 if (cParms == 3)
342 {
343 rc = m_pManager->nextMessageInfo(&paParms[0].u.uint32 /* uMsg */, &paParms[1].u.uint32 /* cParms */);
344 if (RT_FAILURE(rc)) /* No queued messages available? */
345 {
346 if (m_pfnHostCallback) /* Try asking the host. */
347 {
348 VBOXDNDCBHGGETNEXTHOSTMSG data;
349 RT_ZERO(data);
350 data.hdr.uMagic = CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG;
351 rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
352 if (RT_SUCCESS(rc))
353 {
354 paParms[0].u.uint32 = data.uMsg; /* uMsg */
355 paParms[1].u.uint32 = data.cParms; /* cParms */
356 /* Note: paParms[2] was set by the guest as blocking flag. */
357 }
358 }
359 else /* No host callback in place, so drag and drop is not supported by the host. */
360 rc = VERR_NOT_SUPPORTED;
361
362 if (RT_FAILURE(rc))
363 rc = m_pManager->nextMessage(u32Function, cParms, paParms);
364
365 /* Some error occurred or no (new) messages available? */
366 if (RT_FAILURE(rc))
367 {
368 if (paParms[2].u.uint32) /* Blocking flag set? */
369 {
370 /* Defer client returning. */
371 rc = VINF_HGCM_ASYNC_EXECUTE;
372 }
373
374 LogFlowFunc(("Message queue is empty, returning %Rrc to guest\n", rc));
375 }
376 }
377 }
378 break;
379 }
380 case GUEST_DND_CONNECT:
381 {
382 LogFlowFunc(("GUEST_DND_CONNECT\n"));
383 if (cParms >= 2)
384 {
385 const uint8_t idxProto = cParms >= 3 ? 1 : 0;
386
387 VBOXDNDCBCONNECTMSGDATA data;
388 RT_ZERO(data);
389 data.hdr.uMagic = CB_MAGIC_DND_CONNECT;
390 if (cParms >= 3)
391 rc = paParms[0].getUInt32(&data.hdr.uContextID);
392 if (RT_SUCCESS(rc))
393 rc = paParms[idxProto].getUInt32(&data.uProtocol);
394 if (RT_SUCCESS(rc))
395 rc = paParms[idxProto + 1].getUInt32(&data.uFlags);
396 if (RT_SUCCESS(rc))
397 rc = pClient->setProtocol(data.uProtocol);
398 if (RT_SUCCESS(rc))
399 {
400 LogFlowFunc(("Client %RU32 is now using protocol v%RU32\n", pClient->clientId(), pClient->protocol()));
401 DO_HOST_CALLBACK();
402 }
403 }
404 break;
405 }
406 case GUEST_DND_HG_ACK_OP:
407 {
408 LogFlowFunc(("GUEST_DND_HG_ACK_OP\n"));
409
410 VBOXDNDCBHGACKOPDATA data;
411 RT_ZERO(data);
412 data.hdr.uMagic = CB_MAGIC_DND_HG_ACK_OP;
413
414 switch (pClient->protocol())
415 {
416 case 3:
417 {
418 if (cParms == 2)
419 {
420 rc = paParms[0].getUInt32(&data.hdr.uContextID);
421 if (RT_SUCCESS(rc))
422 rc = paParms[1].getUInt32(&data.uAction); /* Get drop action. */
423 }
424 break;
425 }
426
427 case 2:
428 default:
429 {
430 if (cParms == 1)
431 rc = paParms[0].getUInt32(&data.uAction); /* Get drop action. */
432 break;
433 }
434 }
435
436 DO_HOST_CALLBACK();
437 break;
438 }
439 case GUEST_DND_HG_REQ_DATA:
440 {
441 LogFlowFunc(("GUEST_DND_HG_REQ_DATA\n"));
442
443 VBOXDNDCBHGREQDATADATA data;
444 RT_ZERO(data);
445 data.hdr.uMagic = CB_MAGIC_DND_HG_REQ_DATA;
446
447 switch (pClient->protocol())
448 {
449 case 3:
450 {
451 if (cParms == 3)
452 {
453 rc = paParms[0].getUInt32(&data.hdr.uContextID);
454 if (RT_SUCCESS(rc))
455 rc = paParms[1].getPointer((void **)&data.pszFormat, &data.cbFormat);
456 if (RT_SUCCESS(rc))
457 rc = paParms[2].getUInt32(&data.cbFormat);
458 }
459 break;
460 }
461
462 case 2:
463 default:
464 {
465 if (cParms == 1)
466 rc = paParms[0].getPointer((void**)&data.pszFormat, &data.cbFormat);
467 break;
468 }
469 }
470
471 DO_HOST_CALLBACK();
472 break;
473 }
474 case GUEST_DND_HG_EVT_PROGRESS:
475 {
476 LogFlowFunc(("GUEST_DND_HG_EVT_PROGRESS\n"));
477
478 VBOXDNDCBHGEVTPROGRESSDATA data;
479 RT_ZERO(data);
480 data.hdr.uMagic = CB_MAGIC_DND_HG_EVT_PROGRESS;
481
482 switch (pClient->protocol())
483 {
484 case 3:
485 {
486 if (cParms == 4)
487 {
488 rc = paParms[0].getUInt32(&data.uStatus);
489 if (RT_SUCCESS(rc))
490 rc = paParms[1].getUInt32(&data.uStatus);
491 if (RT_SUCCESS(rc))
492 rc = paParms[2].getUInt32(&data.uPercentage);
493 if (RT_SUCCESS(rc))
494 rc = paParms[3].getUInt32(&data.rc);
495 }
496 break;
497 }
498
499 case 2:
500 default:
501 {
502 if (cParms == 3)
503 {
504 rc = paParms[0].getUInt32(&data.uStatus);
505 if (RT_SUCCESS(rc))
506 rc = paParms[1].getUInt32(&data.uPercentage);
507 if (RT_SUCCESS(rc))
508 rc = paParms[2].getUInt32(&data.rc);
509 }
510 break;
511 }
512 }
513
514 DO_HOST_CALLBACK();
515 break;
516 }
517#ifdef VBOX_WITH_DRAG_AND_DROP_GH
518 case GUEST_DND_GH_ACK_PENDING:
519 {
520 LogFlowFunc(("GUEST_DND_GH_ACK_PENDING\n"));
521
522 VBOXDNDCBGHACKPENDINGDATA data;
523 RT_ZERO(data);
524 data.hdr.uMagic = CB_MAGIC_DND_GH_ACK_PENDING;
525
526 switch (pClient->protocol())
527 {
528 case 3:
529 {
530 if (cParms == 5)
531 {
532 rc = paParms[0].getUInt32(&data.hdr.uContextID);
533 if (RT_SUCCESS(rc))
534 rc = paParms[1].getUInt32(&data.uDefAction);
535 if (RT_SUCCESS(rc))
536 rc = paParms[2].getUInt32(&data.uAllActions);
537 if (RT_SUCCESS(rc))
538 rc = paParms[3].getPointer((void**)&data.pszFormat, &data.cbFormat);
539 if (RT_SUCCESS(rc))
540 rc = paParms[4].getUInt32(&data.cbFormat);
541 }
542 break;
543 }
544
545 case 2:
546 default:
547 {
548 if (cParms == 3)
549 {
550 rc = paParms[0].getUInt32(&data.uDefAction);
551 if (RT_SUCCESS(rc))
552 rc = paParms[1].getUInt32(&data.uAllActions);
553 if (RT_SUCCESS(rc))
554 rc = paParms[2].getPointer((void**)&data.pszFormat, &data.cbFormat);
555 }
556 break;
557 }
558 }
559
560 DO_HOST_CALLBACK();
561 break;
562 }
563 /* New since protocol v3. */
564 case GUEST_DND_GH_SND_DATA_HDR:
565 {
566 LogFlowFunc(("GUEST_DND_GH_SND_DATA_HDR\n"));
567 if (cParms == 12)
568 {
569 VBOXDNDCBSNDDATAHDRDATA data;
570 RT_ZERO(data);
571 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_DATA_HDR;
572 rc = paParms[0].getUInt32(&data.hdr.uContextID);
573 if (RT_SUCCESS(rc))
574 rc = paParms[1].getUInt32(&data.data.uFlags);
575 if (RT_SUCCESS(rc))
576 rc = paParms[2].getUInt32(&data.data.uScreenId);
577 if (RT_SUCCESS(rc))
578 rc = paParms[3].getUInt64(&data.data.cbTotal);
579 if (RT_SUCCESS(rc))
580 rc = paParms[4].getUInt32(&data.data.cbMeta);
581 if (RT_SUCCESS(rc))
582 rc = paParms[5].getPointer(&data.data.pvMetaFmt, &data.data.cbMetaFmt);
583 if (RT_SUCCESS(rc))
584 rc = paParms[6].getUInt32(&data.data.cbMetaFmt);
585 if (RT_SUCCESS(rc))
586 rc = paParms[7].getUInt64(&data.data.cObjects);
587 if (RT_SUCCESS(rc))
588 rc = paParms[8].getUInt32(&data.data.enmCompression);
589 if (RT_SUCCESS(rc))
590 rc = paParms[9].getUInt32((uint32_t *)&data.data.enmChecksumType);
591 if (RT_SUCCESS(rc))
592 rc = paParms[10].getPointer(&data.data.pvChecksum, &data.data.cbChecksum);
593 if (RT_SUCCESS(rc))
594 rc = paParms[11].getUInt32(&data.data.cbChecksum);
595
596 LogFlowFunc(("fFlags=0x%x, cbTotalSize=%RU64, cObj=%RU64\n",
597 data.data.uFlags, data.data.cbTotal, data.data.cObjects));
598 DO_HOST_CALLBACK();
599 }
600 break;
601 }
602 case GUEST_DND_GH_SND_DATA:
603 {
604 LogFlowFunc(("GUEST_DND_GH_SND_DATA\n"));
605 switch (pClient->protocol())
606 {
607 case 3:
608 {
609 if (cParms == 5)
610 {
611 VBOXDNDCBSNDDATADATA data;
612 RT_ZERO(data);
613 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_DATA;
614 rc = paParms[0].getUInt32(&data.hdr.uContextID);
615 if (RT_SUCCESS(rc))
616 rc = paParms[1].getPointer((void**)&data.data.u.v3.pvData, &data.data.u.v3.cbData);
617 if (RT_SUCCESS(rc))
618 rc = paParms[2].getUInt32(&data.data.u.v3.cbData);
619 if (RT_SUCCESS(rc))
620 rc = paParms[3].getPointer((void**)&data.data.u.v3.pvChecksum, &data.data.u.v3.cbChecksum);
621 if (RT_SUCCESS(rc))
622 rc = paParms[4].getUInt32(&data.data.u.v3.cbChecksum);
623 DO_HOST_CALLBACK();
624 }
625 break;
626 }
627
628 case 2:
629 default:
630 {
631 if (cParms == 2)
632 {
633 VBOXDNDCBSNDDATADATA data;
634 RT_ZERO(data);
635 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_DATA;
636 rc = paParms[0].getPointer((void**)&data.data.u.v1.pvData, &data.data.u.v1.cbData);
637 if (RT_SUCCESS(rc))
638 rc = paParms[1].getUInt32(&data.data.u.v1.cbTotalSize);
639 DO_HOST_CALLBACK();
640 }
641 break;
642 }
643 }
644 break;
645 }
646 case GUEST_DND_GH_SND_DIR:
647 {
648 LogFlowFunc(("GUEST_DND_GH_SND_DIR\n"));
649
650 VBOXDNDCBSNDDIRDATA data;
651 RT_ZERO(data);
652 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_DIR;
653
654 switch (pClient->protocol())
655 {
656 case 3:
657 {
658 if (cParms == 4)
659 {
660 rc = paParms[0].getUInt32(&data.hdr.uContextID);
661 if (RT_SUCCESS(rc))
662 rc = paParms[0].getPointer((void**)&data.pszPath, &data.cbPath);
663 if (RT_SUCCESS(rc))
664 rc = paParms[1].getUInt32(&data.cbPath);
665 if (RT_SUCCESS(rc))
666 rc = paParms[2].getUInt32(&data.fMode);
667 }
668 break;
669 }
670
671 case 2:
672 default:
673 {
674 if (cParms == 3)
675 {
676 rc = paParms[0].getPointer((void**)&data.pszPath, &data.cbPath);
677 if (RT_SUCCESS(rc))
678 rc = paParms[1].getUInt32(&data.cbPath);
679 if (RT_SUCCESS(rc))
680 rc = paParms[2].getUInt32(&data.fMode);
681 }
682 break;
683 }
684 }
685
686 DO_HOST_CALLBACK();
687 break;
688 }
689 /* New since protocol v2 (>= VBox 5.0). */
690 case GUEST_DND_GH_SND_FILE_HDR:
691 {
692 LogFlowFunc(("GUEST_DND_GH_SND_FILE_HDR\n"));
693 if (cParms == 6)
694 {
695 VBOXDNDCBSNDFILEHDRDATA data;
696 RT_ZERO(data);
697 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_FILE_HDR;
698
699 rc = paParms[0].getUInt32(&data.hdr.uContextID);
700 if (RT_SUCCESS(rc))
701 rc = paParms[1].getPointer((void**)&data.pszFilePath, &data.cbFilePath);
702 if (RT_SUCCESS(rc))
703 rc = paParms[2].getUInt32(&data.cbFilePath);
704 if (RT_SUCCESS(rc))
705 rc = paParms[3].getUInt32(&data.fFlags);
706 if (RT_SUCCESS(rc))
707 rc = paParms[4].getUInt32(&data.fMode);
708 if (RT_SUCCESS(rc))
709 rc = paParms[5].getUInt64(&data.cbSize);
710
711 LogFlowFunc(("pszPath=%s, cbPath=%RU32, fMode=0x%x, cbSize=%RU64\n",
712 data.pszFilePath, data.cbFilePath, data.fMode, data.cbSize));
713 DO_HOST_CALLBACK();
714 }
715 break;
716 }
717 case GUEST_DND_GH_SND_FILE_DATA:
718 {
719 LogFlowFunc(("GUEST_DND_GH_SND_FILE_DATA\n"));
720
721 switch (pClient->protocol())
722 {
723 /* Protocol v3 adds (optional) checksums. */
724 case 3:
725 {
726 if (cParms == 5)
727 {
728 VBOXDNDCBSNDFILEDATADATA data;
729 RT_ZERO(data);
730 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_FILE_DATA;
731
732 rc = paParms[0].getUInt32(&data.hdr.uContextID);
733 if (RT_SUCCESS(rc))
734 rc = paParms[1].getPointer((void**)&data.pvData, &data.cbData);
735 if (RT_SUCCESS(rc))
736 rc = paParms[2].getUInt32(&data.cbData);
737 if (RT_SUCCESS(rc))
738 rc = paParms[3].getPointer((void**)&data.u.v3.pvChecksum, &data.u.v3.cbChecksum);
739 if (RT_SUCCESS(rc))
740 rc = paParms[4].getUInt32(&data.u.v3.cbChecksum);
741
742 LogFlowFunc(("pvData=0x%p, cbData=%RU32\n", data.pvData, data.cbData));
743 DO_HOST_CALLBACK();
744 }
745 break;
746 }
747 /* Protocol v2 only sends the next data chunks to reduce traffic. */
748 case 2:
749 {
750 if (cParms == 3)
751 {
752 VBOXDNDCBSNDFILEDATADATA data;
753 RT_ZERO(data);
754 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_FILE_DATA;
755 rc = paParms[0].getUInt32(&data.hdr.uContextID);
756 if (RT_SUCCESS(rc))
757 rc = paParms[1].getPointer((void**)&data.pvData, &data.cbData);
758 if (RT_SUCCESS(rc))
759 rc = paParms[2].getUInt32(&data.cbData);
760
761 LogFlowFunc(("cbData=%RU32, pvData=0x%p\n", data.cbData, data.pvData));
762 DO_HOST_CALLBACK();
763 }
764 break;
765 }
766 /* Protocol v1 sends the file path and attributes for every file chunk (!). */
767 default:
768 {
769 if (cParms == 5)
770 {
771 VBOXDNDCBSNDFILEDATADATA data;
772 RT_ZERO(data);
773 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_FILE_DATA;
774 uint32_t cTmp;
775 rc = paParms[0].getPointer((void**)&data.u.v1.pszFilePath, &cTmp);
776 if (RT_SUCCESS(rc))
777 rc = paParms[1].getUInt32(&data.u.v1.cbFilePath);
778 if (RT_SUCCESS(rc))
779 rc = paParms[2].getPointer((void**)&data.pvData, &cTmp);
780 if (RT_SUCCESS(rc))
781 rc = paParms[3].getUInt32(&data.cbData);
782 if (RT_SUCCESS(rc))
783 rc = paParms[4].getUInt32(&data.u.v1.fMode);
784
785 LogFlowFunc(("pszFilePath=%s, cbData=%RU32, pvData=0x%p, fMode=0x%x\n",
786 data.u.v1.pszFilePath, data.cbData, data.pvData, data.u.v1.fMode));
787 DO_HOST_CALLBACK();
788 }
789 break;
790 }
791 }
792 break;
793 }
794 case GUEST_DND_GH_EVT_ERROR:
795 {
796 LogFlowFunc(("GUEST_DND_GH_EVT_ERROR\n"));
797
798 VBOXDNDCBEVTERRORDATA data;
799 RT_ZERO(data);
800 data.hdr.uMagic = CB_MAGIC_DND_GH_EVT_ERROR;
801
802 switch (pClient->protocol())
803 {
804 case 3:
805 {
806 if (cParms == 2)
807 {
808 rc = paParms[0].getUInt32(&data.hdr.uContextID);
809 if (RT_SUCCESS(rc))
810 {
811 uint32_t rcOp;
812 rc = paParms[1].getUInt32(&rcOp);
813 if (RT_SUCCESS(rc))
814 data.rc = rcOp;
815 }
816 }
817 break;
818 }
819
820 case 2:
821 default:
822 {
823 if (cParms == 1)
824 {
825 uint32_t rcOp;
826 rc = paParms[0].getUInt32(&rcOp);
827 if (RT_SUCCESS(rc))
828 data.rc = (int32_t)rcOp;
829 }
830 break;
831 }
832 }
833
834 DO_HOST_CALLBACK();
835 break;
836 }
837#endif /* VBOX_WITH_DRAG_AND_DROP_GH */
838 default:
839 {
840 /* All other messages are handled by the DnD manager. */
841 rc = m_pManager->nextMessage(u32Function, cParms, paParms);
842 if (rc == VERR_NO_DATA) /* Manager has no new messsages? Try asking the host. */
843 {
844 if (m_pfnHostCallback)
845 {
846 VBOXDNDCBHGGETNEXTHOSTMSGDATA data;
847 RT_ZERO(data);
848 data.hdr.uMagic = VBOX_DND_CB_MAGIC_MAKE(0 /* uFn */, 0 /* uVer */);
849 data.uMsg = u32Function;
850 data.cParms = cParms;
851 data.paParms = paParms;
852
853 rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
854 if (RT_SUCCESS(rc))
855 {
856 cParms = data.cParms;
857 paParms = data.paParms;
858 }
859 }
860 else /* No host callback in place, so drag and drop is not supported by the host. */
861 rc = VERR_NOT_SUPPORTED;
862 }
863 break;
864 }
865 }
866 }
867
868 /*
869 * If async execution is requested, we didn't notify the guest yet about
870 * completion. The client is queued into the waiters list and will be
871 * notified as soon as a new event is available.
872 */
873 if (rc == VINF_HGCM_ASYNC_EXECUTE)
874 {
875 try
876 {
877 LogFlowFunc(("Deferring guest call completion of client ID=%RU32\n", u32ClientID));
878 m_clientQueue.append(new HGCM::Client(u32ClientID, callHandle,
879 u32Function, cParms, paParms));
880 }
881 catch (std::bad_alloc)
882 {
883 rc = VERR_NO_MEMORY;
884 /* Don't report to guest. */
885 }
886 }
887 else if (m_pHelpers)
888 {
889 /* Complete call on guest side. */
890 m_pHelpers->pfnCallComplete(callHandle, rc);
891 }
892 else
893 rc = VERR_NOT_IMPLEMENTED;
894
895 LogFlowFunc(("Returning rc=%Rrc\n", rc));
896}
897
898int DragAndDropService::hostCall(uint32_t u32Function,
899 uint32_t cParms, VBOXHGCMSVCPARM paParms[])
900{
901 LogFlowFunc(("u32Function=%RU32, cParms=%RU32, cClients=%zu, cQueue=%zu\n",
902 u32Function, cParms, m_clientMap.size(), m_clientQueue.size()));
903
904 int rc;
905 if (u32Function == HOST_DND_SET_MODE)
906 {
907 if (cParms != 1)
908 rc = VERR_INVALID_PARAMETER;
909 else if (paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT)
910 rc = VERR_INVALID_PARAMETER;
911 else
912 rc = modeSet(paParms[0].u.uint32);
913 }
914 else if (modeGet() != VBOX_DRAG_AND_DROP_MODE_OFF)
915 {
916 if (m_clientMap.size()) /* At least one client on the guest connected? */
917 {
918 rc = m_pManager->addMessage(u32Function, cParms, paParms, true /* fAppend */);
919 if (RT_SUCCESS(rc))
920 {
921 if (m_clientQueue.size()) /* Any clients in our queue ready for processing the next command? */
922 {
923 HGCM::Client *pClient = m_clientQueue.first();
924 AssertPtr(pClient);
925
926 /*
927 * Check if this was a request for getting the next host
928 * message. If so, return the message ID and the parameter
929 * count. The message itself has to be queued.
930 */
931 uint32_t uMsg = pClient->message();
932 if (uMsg == GUEST_DND_GET_NEXT_HOST_MSG)
933 {
934 LogFlowFunc(("Client %RU32 is waiting for next host msg\n", pClient->clientId()));
935
936 uint32_t uMsg1;
937 uint32_t cParms1;
938 rc = m_pManager->nextMessageInfo(&uMsg1, &cParms1);
939 if (RT_SUCCESS(rc))
940 {
941 pClient->addMessageInfo(uMsg1, cParms1);
942 if ( m_pHelpers
943 && m_pHelpers->pfnCallComplete)
944 {
945 m_pHelpers->pfnCallComplete(pClient->handle(), rc);
946 }
947
948 m_clientQueue.removeFirst();
949
950 delete pClient;
951 pClient = NULL;
952 }
953 else
954 AssertMsgFailed(("m_pManager::nextMessageInfo failed with rc=%Rrc\n", rc));
955 }
956 else
957 AssertMsgFailed(("Client ID=%RU32 in wrong state with uMsg=%RU32\n",
958 pClient->clientId(), uMsg));
959 }
960 else
961 LogFlowFunc(("All clients busy; delaying execution\n"));
962 }
963 else
964 AssertMsgFailed(("Adding new message of type=%RU32 failed with rc=%Rrc\n",
965 u32Function, rc));
966 }
967 else
968 {
969 /*
970 * Tell the host that the guest does not support drag'n drop.
971 * This might happen due to not installed Guest Additions or
972 * not running VBoxTray/VBoxClient.
973 */
974 rc = VERR_NOT_SUPPORTED;
975 }
976 }
977 else
978 {
979 /* Tell the host that a wrong drag'n drop mode is set. */
980 rc = VERR_ACCESS_DENIED;
981 }
982
983 LogFlowFuncLeaveRC(rc);
984 return rc;
985}
986
987DECLCALLBACK(int) DragAndDropService::progressCallback(uint32_t uStatus, uint32_t uPercentage, int rc, void *pvUser)
988{
989 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
990
991 DragAndDropService *pSelf = static_cast<DragAndDropService *>(pvUser);
992 AssertPtr(pSelf);
993
994 if (pSelf->m_pfnHostCallback)
995 {
996 LogFlowFunc(("GUEST_DND_HG_EVT_PROGRESS: uStatus=%RU32, uPercentage=%RU32, rc=%Rrc\n",
997 uStatus, uPercentage, rc));
998
999 VBOXDNDCBHGEVTPROGRESSDATA data;
1000 data.hdr.uMagic = CB_MAGIC_DND_HG_EVT_PROGRESS;
1001 data.uPercentage = RT_MIN(uPercentage, 100);
1002 data.uStatus = uStatus;
1003 data.rc = rc; /** @todo uin32_t vs. int. */
1004
1005 return pSelf->m_pfnHostCallback(pSelf->m_pvHostData,
1006 GUEST_DND_HG_EVT_PROGRESS,
1007 &data, sizeof(data));
1008 }
1009
1010 return VINF_SUCCESS;
1011}
1012
1013/**
1014 * @copydoc VBOXHGCMSVCLOAD
1015 */
1016extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *pTable)
1017{
1018 return DragAndDropService::svcLoad(pTable);
1019}
1020
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