VirtualBox

source: vbox/trunk/src/VBox/HostServices/DragAndDrop/VBoxDragAndDropSvc.cpp@ 85745

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

DnD: Renaming -- prefix all HGCM function number defines with [GUEST|HOST]_DND_FN_ to better distinguish from other defines.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 46.6 KB
Line 
1/* $Id: VBoxDragAndDropSvc.cpp 85745 2020-08-13 08:37:09Z vboxsync $ */
2/** @file
3 * Drag and Drop Service.
4 */
5
6/*
7 * Copyright (C) 2011-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/** @page pg_svc_dnd Drag and drop HGCM Service
19 *
20 * @sa See src/VBox/Main/src-client/GuestDnDPrivate.cpp for more information.
21 */
22
23
24/*********************************************************************************************************************************
25* Header Files *
26*********************************************************************************************************************************/
27#define LOG_GROUP LOG_GROUP_GUEST_DND
28#include <VBox/GuestHost/DragAndDrop.h>
29#include <VBox/GuestHost/DragAndDropDefs.h>
30#include <VBox/HostServices/Service.h>
31#include <VBox/HostServices/DragAndDropSvc.h>
32#include <VBox/AssertGuest.h>
33
34#include <VBox/err.h>
35
36#include <algorithm>
37#include <list>
38#include <map>
39
40#include "dndmanager.h"
41
42using namespace DragAndDropSvc;
43
44
45/*********************************************************************************************************************************
46* Service class declaration *
47*********************************************************************************************************************************/
48
49class DragAndDropClient : public HGCM::Client
50{
51public:
52
53 DragAndDropClient(uint32_t idClient)
54 : HGCM::Client(idClient)
55 , uProtocolVerDeprecated(0)
56 , fGuestFeatures0(VBOX_DND_GF_NONE)
57 , fGuestFeatures1(VBOX_DND_GF_NONE)
58 {
59 RT_ZERO(m_SvcCtx);
60 }
61
62 virtual ~DragAndDropClient(void)
63 {
64 disconnect();
65 }
66
67public:
68
69 void disconnect(void) RT_NOEXCEPT;
70
71public:
72
73 /** Protocol version used by this client.
74 * Deprecated; only used for keeping backwards compatibility. */
75 uint32_t uProtocolVerDeprecated;
76 /** Guest feature flags, VBOX_DND_GF_0_XXX. */
77 uint64_t fGuestFeatures0;
78 /** Guest feature flags, VBOX_DND_GF_1_XXX. */
79 uint64_t fGuestFeatures1;
80};
81
82/** Map holding pointers to drag and drop clients. Key is the (unique) HGCM client ID. */
83typedef std::map<uint32_t, DragAndDropClient*> DnDClientMap;
84
85/** Simple queue (list) which holds deferred (waiting) clients. */
86typedef std::list<uint32_t> DnDClientQueue;
87
88/**
89 * Specialized drag & drop service class.
90 */
91class DragAndDropService : public HGCM::AbstractService<DragAndDropService>
92{
93public:
94 explicit DragAndDropService(PVBOXHGCMSVCHELPERS pHelpers)
95 : HGCM::AbstractService<DragAndDropService>(pHelpers)
96 , m_pManager(NULL)
97 , m_u32Mode(VBOX_DRAG_AND_DROP_MODE_OFF)
98 {}
99
100protected:
101 int init(VBOXHGCMSVCFNTABLE *pTable) RT_NOEXCEPT RT_OVERRIDE;
102 int uninit(void) RT_NOEXCEPT RT_OVERRIDE;
103 int clientConnect(uint32_t idClient, void *pvClient) RT_NOEXCEPT RT_OVERRIDE;
104 int clientDisconnect(uint32_t idClient, void *pvClient) RT_NOEXCEPT RT_OVERRIDE;
105 int clientQueryFeatures(DragAndDropClient *pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT;
106 int clientReportFeatures(DragAndDropClient *pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT;
107 void guestCall(VBOXHGCMCALLHANDLE callHandle, uint32_t idClient, void *pvClient, uint32_t u32Function,
108 uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT RT_OVERRIDE;
109 int hostCall(uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT RT_OVERRIDE;
110
111private:
112 int modeSet(uint32_t u32Mode) RT_NOEXCEPT;
113 inline uint32_t modeGet(void) const RT_NOEXCEPT
114 { return m_u32Mode; };
115
116 static DECLCALLBACK(int) progressCallback(uint32_t uStatus, uint32_t uPercentage, int rc, void *pvUser);
117
118private:
119 /** Pointer to our DnD manager instance. */
120 DnDManager *m_pManager;
121 /** Map of all connected clients.
122 * The primary key is the (unique) client ID, the secondary value
123 * an allocated pointer to the DragAndDropClient class, managed
124 * by this service class. */
125 DnDClientMap m_clientMap;
126 /** List of all clients which are queued up (deferred return) and ready
127 * to process new commands. The key is the (unique) client ID. */
128 DnDClientQueue m_clientQueue;
129 /** Current drag and drop mode, VBOX_DRAG_AND_DROP_MODE_XXX. */
130 uint32_t m_u32Mode;
131 /** Host feature mask (VBOX_DND_HF_0_XXX) for DND_GUEST_REPORT_FEATURES
132 * and DND_GUEST_QUERY_FEATURES. */
133 uint64_t m_fHostFeatures0;
134};
135
136
137/*********************************************************************************************************************************
138* Client implementation *
139*********************************************************************************************************************************/
140
141/**
142 * Called when the HGCM client disconnected on the guest side.
143 *
144 * This function takes care of the client's data cleanup and also lets the host
145 * know that the client has been disconnected.
146 */
147void DragAndDropClient::disconnect(void) RT_NOEXCEPT
148{
149 LogFlowThisFunc(("uClient=%RU32\n", m_idClient));
150
151 if (IsDeferred())
152 CompleteDeferred(VERR_INTERRUPTED);
153
154 /*
155 * Let the host know.
156 */
157 VBOXDNDCBDISCONNECTMSGDATA data;
158 RT_ZERO(data);
159 /** @todo Magic needed? */
160 /** @todo Add context ID. */
161
162 if (m_SvcCtx.pfnHostCallback)
163 {
164 int rc2 = m_SvcCtx.pfnHostCallback(m_SvcCtx.pvHostData, GUEST_DND_FN_DISCONNECT, &data, sizeof(data));
165 if (RT_FAILURE(rc2))
166 LogFlowFunc(("Warning: Unable to notify host about client %RU32 disconnect, rc=%Rrc\n", m_idClient, rc2));
167 /* Not fatal. */
168 }
169}
170
171
172/*********************************************************************************************************************************
173* Service class implementation *
174*********************************************************************************************************************************/
175
176int DragAndDropService::init(VBOXHGCMSVCFNTABLE *pTable) RT_NOEXCEPT
177{
178 /* Register functions. */
179 pTable->pfnHostCall = svcHostCall;
180 pTable->pfnSaveState = NULL; /* The service is stateless, so the normal */
181 pTable->pfnLoadState = NULL; /* construction done before restoring suffices */
182 pTable->pfnRegisterExtension = svcRegisterExtension;
183 pTable->pfnNotify = NULL;
184
185 /* Drag'n drop mode is disabled by default. */
186 modeSet(VBOX_DRAG_AND_DROP_MODE_OFF);
187
188 /* Set host features. */
189 m_fHostFeatures0 = VBOX_DND_HF_NONE;
190
191 int rc = VINF_SUCCESS;
192
193 try
194 {
195 m_pManager = new DnDManager(&DragAndDropService::progressCallback, this);
196 }
197 catch (std::bad_alloc &)
198 {
199 rc = VERR_NO_MEMORY;
200 }
201
202 LogFlowFuncLeaveRC(rc);
203 return rc;
204}
205
206int DragAndDropService::uninit(void) RT_NOEXCEPT
207{
208 LogFlowFuncEnter();
209
210 if (m_pManager)
211 {
212 delete m_pManager;
213 m_pManager = NULL;
214 }
215
216 DnDClientMap::iterator itClient = m_clientMap.begin();
217 while (itClient != m_clientMap.end())
218 {
219 delete itClient->second;
220 m_clientMap.erase(itClient);
221 itClient = m_clientMap.begin();
222 }
223
224 LogFlowFuncLeave();
225 return VINF_SUCCESS;
226}
227
228int DragAndDropService::clientConnect(uint32_t idClient, void *pvClient) RT_NOEXCEPT
229{
230 RT_NOREF1(pvClient);
231 if (m_clientMap.size() >= UINT8_MAX) /* Don't allow too much clients at the same time. */
232 {
233 AssertMsgFailed(("Maximum number of clients reached\n"));
234 return VERR_MAX_PROCS_REACHED;
235 }
236
237
238 /*
239 * Add client to our client map.
240 */
241 if (m_clientMap.find(idClient) != m_clientMap.end())
242 {
243 LogFunc(("Client %RU32 is already connected!\n", idClient));
244 return VERR_ALREADY_EXISTS;
245 }
246
247 try
248 {
249 DragAndDropClient *pClient = new DragAndDropClient(idClient);
250 pClient->SetSvcContext(m_SvcCtx);
251 m_clientMap[idClient] = pClient;
252 }
253 catch (std::bad_alloc &)
254 {
255 LogFunc(("Client %RU32 - VERR_NO_MEMORY!\n", idClient));
256 return VERR_NO_MEMORY;
257 }
258
259 /*
260 * Reset the message queue as soon as a new clients connect
261 * to ensure that every client has the same state.
262 */
263 if (m_pManager)
264 m_pManager->Reset();
265
266 LogFlowFunc(("Client %RU32 connected (VINF_SUCCESS)\n", idClient));
267 return VINF_SUCCESS;
268}
269
270int DragAndDropService::clientDisconnect(uint32_t idClient, void *pvClient) RT_NOEXCEPT
271{
272 RT_NOREF1(pvClient);
273
274 /* Client not found? Bail out early. */
275 DnDClientMap::iterator itClient = m_clientMap.find(idClient);
276 if (itClient == m_clientMap.end())
277 {
278 LogFunc(("Client %RU32 not found!\n", idClient));
279 return VERR_NOT_FOUND;
280 }
281
282 /*
283 * Remove from waiters queue.
284 */
285 m_clientQueue.remove(idClient);
286
287 /*
288 * Remove from client map and deallocate.
289 */
290 AssertPtr(itClient->second);
291 delete itClient->second;
292
293 m_clientMap.erase(itClient);
294
295 LogFlowFunc(("Client %RU32 disconnected\n", idClient));
296 return VINF_SUCCESS;
297}
298
299/**
300 * Implements GUEST_DND_FN_REPORT_FEATURES.
301 *
302 * @returns VBox status code.
303 * @retval VINF_HGCM_ASYNC_EXECUTE on success (we complete the message here).
304 * @retval VERR_ACCESS_DENIED if not master
305 * @retval VERR_INVALID_PARAMETER if bit 63 in the 2nd parameter isn't set.
306 * @retval VERR_WRONG_PARAMETER_COUNT
307 *
308 * @param pClient The client state.
309 * @param hCall The client's call handle.
310 * @param cParms Number of parameters.
311 * @param paParms Array of parameters.
312 */
313int DragAndDropService::clientReportFeatures(DragAndDropClient *pClient,
314 VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT
315{
316 /*
317 * Validate the request.
318 */
319 ASSERT_GUEST_RETURN(cParms == 2, VERR_WRONG_PARAMETER_COUNT);
320 ASSERT_GUEST_RETURN(paParms[0].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE);
321 uint64_t const fFeatures0 = paParms[0].u.uint64;
322 ASSERT_GUEST_RETURN(paParms[1].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE);
323 uint64_t const fFeatures1 = paParms[1].u.uint64;
324 ASSERT_GUEST_RETURN(fFeatures1 & VBOX_DND_GF_1_MUST_BE_ONE, VERR_INVALID_PARAMETER);
325
326 /*
327 * Do the work.
328 */
329 paParms[0].u.uint64 = m_fHostFeatures0;
330 paParms[1].u.uint64 = 0;
331
332 int rc = pClient->Complete(hCall, VINF_SUCCESS);
333 if (RT_SUCCESS(rc))
334 {
335 pClient->fGuestFeatures0 = fFeatures0;
336 pClient->fGuestFeatures1 = fFeatures1;
337 Log(("[Client %RU32] features: %#RX64 %#RX64\n", pClient->GetClientID(), fFeatures0, fFeatures1));
338 }
339 else
340 LogFunc(("pfnCallComplete -> %Rrc\n", rc));
341
342 return VINF_HGCM_ASYNC_EXECUTE;
343}
344
345/**
346 * Implements GUEST_DND_FN_QUERY_FEATURES.
347 *
348 * @returns VBox status code.
349 * @retval VINF_HGCM_ASYNC_EXECUTE on success (we complete the message here).
350 * @retval VERR_WRONG_PARAMETER_COUNT
351 *
352 * @param pClient The client state.
353 * @param hCall The client's call handle.
354 * @param cParms Number of parameters.
355 * @param paParms Array of parameters.
356 */
357int DragAndDropService::clientQueryFeatures(DragAndDropClient *pClient,
358 VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT
359{
360 /*
361 * Validate the request.
362 */
363 ASSERT_GUEST_RETURN(cParms == 2, VERR_WRONG_PARAMETER_COUNT);
364 ASSERT_GUEST_RETURN(paParms[0].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE);
365 ASSERT_GUEST_RETURN(paParms[1].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE);
366 ASSERT_GUEST(paParms[1].u.uint64 & RT_BIT_64(63));
367
368 /*
369 * Do the work.
370 */
371 paParms[0].u.uint64 = m_fHostFeatures0;
372 paParms[1].u.uint64 = 0;
373
374 int rc = pClient->Complete(hCall, VINF_SUCCESS);
375 if (RT_FAILURE(rc))
376 LogFunc(("pfnCallComplete -> %Rrc\n", rc));
377
378 return VINF_HGCM_ASYNC_EXECUTE;
379}
380
381int DragAndDropService::modeSet(uint32_t u32Mode) RT_NOEXCEPT
382{
383#ifndef VBOX_WITH_DRAG_AND_DROP_GH
384 if ( u32Mode == VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST
385 || u32Mode == VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL)
386 {
387 m_u32Mode = VBOX_DRAG_AND_DROP_MODE_OFF;
388 return VERR_NOT_SUPPORTED;
389 }
390#endif
391
392 switch (u32Mode)
393 {
394 case VBOX_DRAG_AND_DROP_MODE_OFF:
395 case VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST:
396 case VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST:
397 case VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL:
398 m_u32Mode = u32Mode;
399 break;
400
401 default:
402 m_u32Mode = VBOX_DRAG_AND_DROP_MODE_OFF;
403 break;
404 }
405
406 return VINF_SUCCESS;
407}
408
409void DragAndDropService::guestCall(VBOXHGCMCALLHANDLE callHandle, uint32_t idClient,
410 void *pvClient, uint32_t u32Function,
411 uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT
412{
413 RT_NOREF1(pvClient);
414 LogFlowFunc(("idClient=%RU32, u32Function=%RU32, cParms=%RU32\n", idClient, u32Function, cParms));
415
416 /* Check if we've the right mode set. */
417 int rc = VERR_ACCESS_DENIED; /* Play safe. */
418 switch (u32Function)
419 {
420 case GUEST_DND_FN_GET_NEXT_HOST_MSG:
421 {
422 if (modeGet() != VBOX_DRAG_AND_DROP_MODE_OFF)
423 rc = VINF_SUCCESS;
424 else
425 {
426 LogFlowFunc(("DnD disabled, deferring request\n"));
427 rc = VINF_HGCM_ASYNC_EXECUTE;
428 }
429 break;
430 }
431
432 /* New since protocol v2. */
433 case GUEST_DND_FN_CONNECT:
434 RT_FALL_THROUGH();
435 /* New since VBox 6.1.x. */
436 case GUEST_DND_FN_REPORT_FEATURES:
437 RT_FALL_THROUGH();
438 /* New since VBox 6.1.x. */
439 case GUEST_DND_FN_QUERY_FEATURES:
440 {
441 /*
442 * Never block these calls, as the clients issues those when
443 * initializing and might get stuck if drag and drop is set to "disabled" at
444 * that time.
445 */
446 rc = VINF_SUCCESS;
447 break;
448 }
449
450 case GUEST_DND_FN_HG_ACK_OP:
451 case GUEST_DND_FN_HG_REQ_DATA:
452 case GUEST_DND_FN_HG_EVT_PROGRESS:
453 {
454 if ( modeGet() == VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
455 || modeGet() == VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST)
456 rc = VINF_SUCCESS;
457 else
458 LogFlowFunc(("Host -> Guest DnD mode disabled, failing request\n"));
459 break;
460 }
461
462 case GUEST_DND_FN_GH_ACK_PENDING:
463 case GUEST_DND_FN_GH_SND_DATA_HDR:
464 case GUEST_DND_FN_GH_SND_DATA:
465 case GUEST_DND_FN_GH_SND_DIR:
466 case GUEST_DND_FN_GH_SND_FILE_HDR:
467 case GUEST_DND_FN_GH_SND_FILE_DATA:
468 case GUEST_DND_FN_GH_EVT_ERROR:
469 {
470#ifdef VBOX_WITH_DRAG_AND_DROP_GH
471 if ( modeGet() == VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
472 || modeGet() == VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST)
473 rc = VINF_SUCCESS;
474 else
475#endif
476 LogFlowFunc(("Guest -> Host DnD mode disabled, failing request\n"));
477 break;
478 }
479
480 default:
481 /* Reach through to DnD manager. */
482 rc = VINF_SUCCESS;
483 break;
484 }
485
486#ifdef DEBUG_andy
487 LogFlowFunc(("Mode (%RU32) check rc=%Rrc\n", modeGet(), rc));
488#endif
489
490#define DO_HOST_CALLBACK(); \
491 if ( RT_SUCCESS(rc) \
492 && m_SvcCtx.pfnHostCallback) \
493 { \
494 rc = m_SvcCtx.pfnHostCallback(m_SvcCtx.pvHostData, u32Function, &data, sizeof(data)); \
495 }
496
497 /*
498 * Lookup client.
499 */
500 DragAndDropClient *pClient = NULL;
501
502 DnDClientMap::iterator itClient = m_clientMap.find(idClient);
503 if (itClient != m_clientMap.end())
504 {
505 pClient = itClient->second;
506 AssertPtr(pClient);
507 }
508 else
509 {
510 LogFunc(("Client %RU32 was not found\n", idClient));
511 rc = VERR_NOT_FOUND;
512 }
513
514/* Verifies that an uint32 parameter has the expected buffer size set.
515 * Will set rc to VERR_INVALID_PARAMETER otherwise. See #9777. */
516#define VERIFY_BUFFER_SIZE_UINT32(a_ParmUInt32, a_SizeExpected) \
517do { \
518 uint32_t cbTemp = 0; \
519 rc = HGCMSvcGetU32(&a_ParmUInt32, &cbTemp); \
520 ASSERT_GUEST_BREAK(RT_SUCCESS(rc) && cbTemp == a_SizeExpected); \
521} while (0)
522
523/* Gets the context ID from the first parameter and store it into the data header.
524 * Then increments idxParm by one if more than one parameter is available. */
525#define GET_CONTEXT_ID_PARM0() \
526 if (fHasCtxID) \
527 { \
528 ASSERT_GUEST_BREAK(cParms >= 1); \
529 rc = HGCMSvcGetU32(&paParms[0], &data.hdr.uContextID); \
530 ASSERT_GUEST_BREAK(RT_SUCCESS(rc)); \
531 if (cParms > 1) \
532 idxParm++; \
533 }
534
535 if (rc == VINF_SUCCESS) /* Note: rc might be VINF_HGCM_ASYNC_EXECUTE! */
536 {
537 rc = VERR_INVALID_PARAMETER; /* Play safe by default. */
538
539 /* Whether the client's advertised protocol sends context IDs with commands. */
540 const bool fHasCtxID = pClient->uProtocolVerDeprecated >= 3;
541
542 /* Current parameter index to process. */
543 unsigned idxParm = 0;
544
545 switch (u32Function)
546 {
547 /*
548 * Note: Older VBox versions with enabled DnD guest->host support (< 5.0)
549 * used the same message ID (300) for GUEST_DND_FN_GET_NEXT_HOST_MSG and
550 * HOST_DND_FN_GH_REQ_PENDING, which led this service returning
551 * VERR_INVALID_PARAMETER when the guest wanted to actually
552 * handle HOST_DND_FN_GH_REQ_PENDING.
553 */
554 case GUEST_DND_FN_GET_NEXT_HOST_MSG:
555 {
556 LogFlowFunc(("GUEST_DND_FN_GET_NEXT_HOST_MSG\n"));
557 if (cParms == 3)
558 {
559 rc = m_pManager->GetNextMsgInfo(&paParms[0].u.uint32 /* uMsg */, &paParms[1].u.uint32 /* cParms */);
560 if (RT_FAILURE(rc)) /* No queued messages available? */
561 {
562 if (m_SvcCtx.pfnHostCallback) /* Try asking the host. */
563 {
564 VBOXDNDCBHGGETNEXTHOSTMSG data;
565 RT_ZERO(data);
566 data.hdr.uMagic = CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG;
567 rc = m_SvcCtx.pfnHostCallback(m_SvcCtx.pvHostData, u32Function, &data, sizeof(data));
568 if (RT_SUCCESS(rc))
569 {
570 paParms[0].u.uint32 = data.uMsg; /* uMsg */
571 paParms[1].u.uint32 = data.cParms; /* cParms */
572 /* Note: paParms[2] was set by the guest as blocking flag. */
573 }
574 }
575 else /* No host callback in place, so drag and drop is not supported by the host. */
576 rc = VERR_NOT_SUPPORTED;
577
578 if (RT_FAILURE(rc))
579 rc = m_pManager->GetNextMsg(u32Function, cParms, paParms);
580
581 /* Some error occurred or no (new) messages available? */
582 if (RT_FAILURE(rc))
583 {
584 uint32_t fFlags = 0;
585 int rc2 = HGCMSvcGetU32(&paParms[2], &fFlags);
586 if ( RT_SUCCESS(rc2)
587 && fFlags) /* Blocking flag set? */
588 {
589 /* Defer client returning. */
590 rc = VINF_HGCM_ASYNC_EXECUTE;
591 }
592 else
593 rc = VERR_INVALID_PARAMETER;
594
595 LogFlowFunc(("Message queue is empty, returning %Rrc to guest\n", rc));
596 }
597 }
598 }
599 break;
600 }
601 case GUEST_DND_FN_CONNECT:
602 {
603 LogFlowFunc(("GUEST_DND_FN_CONNECT\n"));
604
605 ASSERT_GUEST_BREAK(cParms >= 2);
606
607 VBOXDNDCBCONNECTDATA data;
608 RT_ZERO(data);
609 data.hdr.uMagic = CB_MAGIC_DND_CONNECT;
610
611 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.hdr.uContextID); \
612 ASSERT_GUEST_RC_BREAK(rc);
613 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.uProtocolVersion);
614 ASSERT_GUEST_RC_BREAK(rc);
615 rc = HGCMSvcGetU32(&paParms[idxParm], &data.fFlags);
616 ASSERT_GUEST_RC_BREAK(rc);
617
618 unsigned uProtocolVer = 3; /* The protocol version we're going to use. */
619
620 /* Make sure we're only setting a protocl version we're supporting on the host. */
621 if (data.uProtocolVersion > uProtocolVer)
622 data.uProtocolVersion = uProtocolVer;
623
624 pClient->uProtocolVerDeprecated = data.uProtocolVersion;
625
626 /* Return the highest protocol version we're supporting. */
627 AssertBreak(idxParm);
628 ASSERT_GUEST_BREAK(idxParm);
629 paParms[idxParm - 1].u.uint32 = data.uProtocolVersion;
630
631 LogFlowFunc(("Client %RU32 is now using protocol v%RU32\n",
632 pClient->GetClientID(), pClient->uProtocolVerDeprecated));
633
634 DO_HOST_CALLBACK();
635 break;
636 }
637 case GUEST_DND_FN_REPORT_FEATURES:
638 {
639 LogFlowFunc(("GUEST_DND_FN_REPORT_FEATURES\n"));
640 rc = clientReportFeatures(pClient, callHandle, cParms, paParms);
641 if (RT_SUCCESS(rc))
642 {
643 VBOXDNDCBREPORTFEATURESDATA data;
644 RT_ZERO(data);
645 data.hdr.uMagic = CB_MAGIC_DND_REPORT_FEATURES;
646
647 data.fGuestFeatures0 = pClient->fGuestFeatures0;
648 /* fGuestFeatures1 is not used yet. */
649
650 /* Don't touch initial rc. */
651 int rc2 = m_SvcCtx.pfnHostCallback(m_SvcCtx.pvHostData, u32Function, &data, sizeof(data));
652 AssertRC(rc2);
653 }
654 break;
655 }
656 case GUEST_DND_FN_QUERY_FEATURES:
657 {
658 LogFlowFunc(("GUEST_DND_FN_QUERY_FEATURES"));
659 rc = clientQueryFeatures(pClient, callHandle, cParms, paParms);
660 break;
661 }
662 case GUEST_DND_FN_HG_ACK_OP:
663 {
664 LogFlowFunc(("GUEST_DND_FN_HG_ACK_OP\n"));
665
666 ASSERT_GUEST_BREAK(cParms >= 2);
667
668 VBOXDNDCBHGACKOPDATA data;
669 RT_ZERO(data);
670 data.hdr.uMagic = CB_MAGIC_DND_HG_ACK_OP;
671
672 GET_CONTEXT_ID_PARM0();
673 rc = HGCMSvcGetU32(&paParms[idxParm], &data.uAction); /* Get drop action. */
674 ASSERT_GUEST_RC_BREAK(rc);
675
676 DO_HOST_CALLBACK();
677 break;
678 }
679 case GUEST_DND_FN_HG_REQ_DATA:
680 {
681 LogFlowFunc(("GUEST_DND_FN_HG_REQ_DATA\n"));
682
683 VBOXDNDCBHGREQDATADATA data;
684 RT_ZERO(data);
685 data.hdr.uMagic = CB_MAGIC_DND_HG_REQ_DATA;
686
687 switch (pClient->uProtocolVerDeprecated)
688 {
689 case 3:
690 {
691 ASSERT_GUEST_BREAK(cParms == 3);
692 GET_CONTEXT_ID_PARM0();
693 rc = HGCMSvcGetPv(&paParms[idxParm++], (void **)&data.pszFormat, &data.cbFormat);
694 ASSERT_GUEST_RC_BREAK(rc);
695 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm], data.cbFormat);
696 break;
697 }
698
699 case 2:
700 RT_FALL_THROUGH();
701 default:
702 {
703 ASSERT_GUEST_BREAK(cParms == 1);
704 rc = HGCMSvcGetPv(&paParms[idxParm], (void**)&data.pszFormat, &data.cbFormat);
705 ASSERT_GUEST_RC_BREAK(rc);
706 break;
707 }
708 }
709
710 DO_HOST_CALLBACK();
711 break;
712 }
713 case GUEST_DND_FN_HG_EVT_PROGRESS:
714 {
715 LogFlowFunc(("GUEST_DND_FN_HG_EVT_PROGRESS\n"));
716
717 ASSERT_GUEST_BREAK(cParms >= 3);
718
719 VBOXDNDCBHGEVTPROGRESSDATA data;
720 RT_ZERO(data);
721 data.hdr.uMagic = CB_MAGIC_DND_HG_EVT_PROGRESS;
722
723 GET_CONTEXT_ID_PARM0();
724 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.uStatus);
725 ASSERT_GUEST_RC_BREAK(rc);
726 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.uPercentage);
727 ASSERT_GUEST_RC_BREAK(rc);
728 rc = HGCMSvcGetU32(&paParms[idxParm], &data.rc);
729 ASSERT_GUEST_RC_BREAK(rc);
730
731 DO_HOST_CALLBACK();
732 break;
733 }
734#ifdef VBOX_WITH_DRAG_AND_DROP_GH
735 case GUEST_DND_FN_GH_ACK_PENDING:
736 {
737 LogFlowFunc(("GUEST_DND_FN_GH_ACK_PENDING\n"));
738
739 VBOXDNDCBGHACKPENDINGDATA data;
740 RT_ZERO(data);
741 data.hdr.uMagic = CB_MAGIC_DND_GH_ACK_PENDING;
742
743 switch (pClient->uProtocolVerDeprecated)
744 {
745 case 3:
746 {
747 ASSERT_GUEST_BREAK(cParms == 5);
748 GET_CONTEXT_ID_PARM0();
749 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.uDefAction);
750 ASSERT_GUEST_RC_BREAK(rc);
751 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.uAllActions);
752 ASSERT_GUEST_RC_BREAK(rc);
753 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.pszFormat, &data.cbFormat);
754 ASSERT_GUEST_RC_BREAK(rc);
755 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm], data.cbFormat);
756 break;
757 }
758
759 case 2:
760 default:
761 {
762 ASSERT_GUEST_BREAK(cParms == 3);
763 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.uDefAction);
764 ASSERT_GUEST_RC_BREAK(rc);
765 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.uAllActions);
766 ASSERT_GUEST_RC_BREAK(rc);
767 rc = HGCMSvcGetPv(&paParms[idxParm], (void**)&data.pszFormat, &data.cbFormat);
768 ASSERT_GUEST_RC_BREAK(rc);
769 break;
770 }
771 }
772
773 DO_HOST_CALLBACK();
774 break;
775 }
776 /* New since protocol v3. */
777 case GUEST_DND_FN_GH_SND_DATA_HDR:
778 {
779 LogFlowFunc(("GUEST_DND_FN_GH_SND_DATA_HDR\n"));
780
781 ASSERT_GUEST_BREAK(cParms == 12);
782
783 VBOXDNDCBSNDDATAHDRDATA data;
784 RT_ZERO(data);
785 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_DATA_HDR;
786
787 GET_CONTEXT_ID_PARM0();
788 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.data.uFlags);
789 ASSERT_GUEST_RC_BREAK(rc);
790 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.data.uScreenId);
791 ASSERT_GUEST_RC_BREAK(rc);
792 rc = HGCMSvcGetU64(&paParms[idxParm++], &data.data.cbTotal);
793 ASSERT_GUEST_RC_BREAK(rc);
794 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.data.cbMeta);
795 ASSERT_GUEST_RC_BREAK(rc);
796 ASSERT_GUEST_BREAK(data.data.cbMeta <= data.data.cbTotal);
797 rc = HGCMSvcGetPv(&paParms[idxParm++], &data.data.pvMetaFmt, &data.data.cbMetaFmt);
798 ASSERT_GUEST_RC_BREAK(rc);
799 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm++], data.data.cbMetaFmt);
800 rc = HGCMSvcGetU64(&paParms[idxParm++], &data.data.cObjects);
801 ASSERT_GUEST_RC_BREAK(rc);
802 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.data.enmCompression);
803 ASSERT_GUEST_RC_BREAK(rc);
804 rc = HGCMSvcGetU32(&paParms[idxParm++], (uint32_t *)&data.data.enmChecksumType);
805 ASSERT_GUEST_RC_BREAK(rc);
806 rc = HGCMSvcGetPv(&paParms[idxParm++], &data.data.pvChecksum, &data.data.cbChecksum);
807 ASSERT_GUEST_RC_BREAK(rc);
808 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm], data.data.cbChecksum);
809
810 DO_HOST_CALLBACK();
811 break;
812 }
813 case GUEST_DND_FN_GH_SND_DATA:
814 {
815 LogFlowFunc(("GUEST_DND_FN_GH_SND_DATA\n"));
816
817 switch (pClient->uProtocolVerDeprecated)
818 {
819 case 3:
820 {
821 ASSERT_GUEST_BREAK(cParms == 5);
822
823 VBOXDNDCBSNDDATADATA data;
824 RT_ZERO(data);
825 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_DATA;
826
827 GET_CONTEXT_ID_PARM0();
828 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.data.u.v3.pvData, &data.data.u.v3.cbData);
829 ASSERT_GUEST_RC_BREAK(rc);
830 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm++], data.data.u.v3.cbData);
831 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.data.u.v3.pvChecksum, &data.data.u.v3.cbChecksum);
832 ASSERT_GUEST_RC_BREAK(rc);
833 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm], data.data.u.v3.cbChecksum);
834
835 DO_HOST_CALLBACK();
836 break;
837 }
838
839 case 2:
840 default:
841 {
842 ASSERT_GUEST_BREAK(cParms == 2);
843
844 VBOXDNDCBSNDDATADATA data;
845 RT_ZERO(data);
846 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_DATA;
847
848 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.data.u.v1.pvData, &data.data.u.v1.cbData);
849 ASSERT_GUEST_RC_BREAK(rc);
850 rc = HGCMSvcGetU32(&paParms[idxParm], &data.data.u.v1.cbTotalSize);
851 ASSERT_GUEST_RC_BREAK(rc);
852
853 DO_HOST_CALLBACK();
854 break;
855 }
856 }
857 break;
858 }
859 case GUEST_DND_FN_GH_SND_DIR:
860 {
861 LogFlowFunc(("GUEST_DND_FN_GH_SND_DIR\n"));
862
863 ASSERT_GUEST_BREAK(cParms >= 3);
864
865 VBOXDNDCBSNDDIRDATA data;
866 RT_ZERO(data);
867 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_DIR;
868
869 GET_CONTEXT_ID_PARM0();
870 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.pszPath, &data.cbPath);
871 ASSERT_GUEST_RC_BREAK(rc);
872 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm++], data.cbPath);
873 rc = HGCMSvcGetU32(&paParms[idxParm], &data.fMode);
874 ASSERT_GUEST_RC_BREAK(rc);
875
876 DO_HOST_CALLBACK();
877 break;
878 }
879 /* New since protocol v2 (>= VBox 5.0). */
880 case GUEST_DND_FN_GH_SND_FILE_HDR:
881 {
882 LogFlowFunc(("GUEST_DND_FN_GH_SND_FILE_HDR\n"));
883
884 ASSERT_GUEST_BREAK(cParms == 6);
885
886 VBOXDNDCBSNDFILEHDRDATA data;
887 RT_ZERO(data);
888 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_FILE_HDR;
889
890 GET_CONTEXT_ID_PARM0();
891 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.pszFilePath, &data.cbFilePath);
892 ASSERT_GUEST_RC_BREAK(rc);
893 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm++], data.cbFilePath);
894 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.fFlags);
895 ASSERT_GUEST_RC_BREAK(rc);
896 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.fMode);
897 ASSERT_GUEST_RC_BREAK(rc);
898 rc = HGCMSvcGetU64(&paParms[idxParm], &data.cbSize);
899 ASSERT_GUEST_RC_BREAK(rc);
900
901 DO_HOST_CALLBACK();
902 break;
903 }
904 case GUEST_DND_FN_GH_SND_FILE_DATA:
905 {
906 LogFlowFunc(("GUEST_DND_FN_GH_SND_FILE_DATA\n"));
907
908 switch (pClient->uProtocolVerDeprecated)
909 {
910 /* Protocol v3 adds (optional) checksums. */
911 case 3:
912 {
913 ASSERT_GUEST_BREAK(cParms == 5);
914
915 VBOXDNDCBSNDFILEDATADATA data;
916 RT_ZERO(data);
917 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_FILE_DATA;
918
919 GET_CONTEXT_ID_PARM0();
920 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.pvData, &data.cbData);
921 ASSERT_GUEST_RC_BREAK(rc);
922 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm++], data.cbData);
923 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.u.v3.pvChecksum, &data.u.v3.cbChecksum);
924 ASSERT_GUEST_RC_BREAK(rc);
925 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm], data.u.v3.cbChecksum);
926
927 DO_HOST_CALLBACK();
928 break;
929 }
930 /* Protocol v2 only sends the next data chunks to reduce traffic. */
931 case 2:
932 {
933 ASSERT_GUEST_BREAK(cParms == 3);
934
935 VBOXDNDCBSNDFILEDATADATA data;
936 RT_ZERO(data);
937 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_FILE_DATA;
938
939 GET_CONTEXT_ID_PARM0();
940 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.pvData, &data.cbData);
941 ASSERT_GUEST_RC_BREAK(rc);
942 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm], data.cbData);
943
944 DO_HOST_CALLBACK();
945 break;
946 }
947 /* Protocol v1 sends the file path and attributes for every file chunk (!). */
948 default:
949 {
950 ASSERT_GUEST_BREAK(cParms == 5);
951
952 VBOXDNDCBSNDFILEDATADATA data;
953 RT_ZERO(data);
954 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_FILE_DATA;
955
956 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.u.v1.pszFilePath, &data.u.v1.cbFilePath);
957 ASSERT_GUEST_RC_BREAK(rc);
958 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm++], data.u.v1.cbFilePath);
959 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.pvData, &data.cbData);
960 ASSERT_GUEST_RC_BREAK(rc);
961 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm++], data.cbData);
962 rc = HGCMSvcGetU32(&paParms[idxParm], &data.u.v1.fMode);
963 ASSERT_GUEST_RC_BREAK(rc);
964
965 DO_HOST_CALLBACK();
966 break;
967 }
968 }
969 break;
970 }
971 case GUEST_DND_FN_GH_EVT_ERROR:
972 {
973 LogFlowFunc(("GUEST_DND_FN_GH_EVT_ERROR\n"));
974
975 ASSERT_GUEST_BREAK(cParms >= 1);
976
977 VBOXDNDCBEVTERRORDATA data;
978 RT_ZERO(data);
979 data.hdr.uMagic = CB_MAGIC_DND_GH_EVT_ERROR;
980
981 GET_CONTEXT_ID_PARM0();
982 rc = HGCMSvcGetU32(&paParms[idxParm], (uint32_t *)&data.rc);
983 ASSERT_GUEST_RC_BREAK(rc);
984
985 DO_HOST_CALLBACK();
986 break;
987 }
988#endif /* VBOX_WITH_DRAG_AND_DROP_GH */
989
990 default:
991 {
992 /* All other messages are handled by the DnD manager. */
993 rc = m_pManager->GetNextMsg(u32Function, cParms, paParms);
994 if (rc == VERR_NO_DATA) /* Manager has no new messsages? Try asking the host. */
995 {
996 if (m_SvcCtx.pfnHostCallback)
997 {
998 VBOXDNDCBHGGETNEXTHOSTMSGDATA data;
999 RT_ZERO(data);
1000
1001 data.hdr.uMagic = VBOX_DND_CB_MAGIC_MAKE(0 /* uFn */, 0 /* uVer */);
1002
1003 data.uMsg = u32Function;
1004 data.cParms = cParms;
1005 data.paParms = paParms;
1006
1007 rc = m_SvcCtx.pfnHostCallback(m_SvcCtx.pvHostData, u32Function,
1008 &data, sizeof(data));
1009 if (RT_SUCCESS(rc))
1010 {
1011 cParms = data.cParms;
1012 paParms = data.paParms;
1013 }
1014 else
1015 {
1016 /*
1017 * In case the guest is too fast asking for the next message
1018 * and the host did not supply it yet, just defer the client's
1019 * return until a response from the host available.
1020 */
1021 LogFlowFunc(("No new messages from the host (yet), deferring request: %Rrc\n", rc));
1022 rc = VINF_HGCM_ASYNC_EXECUTE;
1023 }
1024 }
1025 else /* No host callback in place, so drag and drop is not supported by the host. */
1026 rc = VERR_NOT_SUPPORTED;
1027 }
1028 break;
1029 }
1030 }
1031 }
1032
1033#undef VERIFY_BUFFER_SIZE_UINT32
1034
1035 /*
1036 * If async execution is requested, we didn't notify the guest yet about
1037 * completion. The client is queued into the waiters list and will be
1038 * notified as soon as a new event is available.
1039 */
1040 if (rc == VINF_HGCM_ASYNC_EXECUTE)
1041 {
1042 try
1043 {
1044 AssertPtr(pClient);
1045 pClient->SetDeferred(callHandle, u32Function, cParms, paParms);
1046 m_clientQueue.push_back(idClient);
1047 }
1048 catch (std::bad_alloc &)
1049 {
1050 rc = VERR_NO_MEMORY;
1051 /* Don't report to guest. */
1052 }
1053 }
1054 else if (pClient)
1055 pClient->Complete(callHandle, rc);
1056 else
1057 {
1058 AssertMsgFailed(("Guest call failed with %Rrc\n", rc));
1059 rc = VERR_NOT_IMPLEMENTED;
1060 }
1061
1062 LogFlowFunc(("Returning rc=%Rrc\n", rc));
1063}
1064
1065int DragAndDropService::hostCall(uint32_t u32Function,
1066 uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT
1067{
1068 LogFlowFunc(("u32Function=%RU32, cParms=%RU32, cClients=%zu, cQueue=%zu\n",
1069 u32Function, cParms, m_clientMap.size(), m_clientQueue.size()));
1070
1071 int rc;
1072 bool fSendToGuest = false; /* Whether to send the message down to the guest side or not. */
1073
1074 switch (u32Function)
1075 {
1076 case HOST_DND_FN_SET_MODE:
1077 {
1078 if (cParms != 1)
1079 rc = VERR_INVALID_PARAMETER;
1080 else if (paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT)
1081 rc = VERR_INVALID_PARAMETER;
1082 else
1083 rc = modeSet(paParms[0].u.uint32);
1084 break;
1085 }
1086
1087 case HOST_DND_FN_CANCEL:
1088 {
1089 LogFlowFunc(("Cancelling all waiting clients ...\n"));
1090
1091 /* Reset the message queue as the host cancelled the whole operation. */
1092 m_pManager->Reset();
1093
1094 rc = m_pManager->AddMsg(u32Function, cParms, paParms, true /* fAppend */);
1095 if (RT_FAILURE(rc))
1096 {
1097 AssertMsgFailed(("Adding new message of type=%RU32 failed with rc=%Rrc\n", u32Function, rc));
1098 break;
1099 }
1100
1101 /*
1102 * Wake up all deferred clients and tell them to process
1103 * the cancelling message next.
1104 */
1105 DnDClientQueue::iterator itQueue = m_clientQueue.begin();
1106 while (itQueue != m_clientQueue.end())
1107 {
1108 DnDClientMap::iterator itClient = m_clientMap.find(*itQueue);
1109 Assert(itClient != m_clientMap.end());
1110
1111 DragAndDropClient *pClient = itClient->second;
1112 AssertPtr(pClient);
1113
1114 int rc2 = pClient->SetDeferredMsgInfo(HOST_DND_FN_CANCEL,
1115 /* Protocol v3+ also contains the context ID. */
1116 pClient->uProtocolVerDeprecated >= 3 ? 1 : 0);
1117 pClient->CompleteDeferred(rc2);
1118
1119 m_clientQueue.erase(itQueue);
1120 itQueue = m_clientQueue.begin();
1121 }
1122
1123 Assert(m_clientQueue.empty());
1124
1125 /* Tell the host that everything went well. */
1126 rc = VINF_SUCCESS;
1127 break;
1128 }
1129
1130 case HOST_DND_FN_HG_EVT_ENTER:
1131 {
1132 /* Reset the message queue as a new DnD operation just began. */
1133 m_pManager->Reset();
1134
1135 fSendToGuest = true;
1136 rc = VINF_SUCCESS;
1137 break;
1138 }
1139
1140 default:
1141 {
1142 fSendToGuest = true;
1143 rc = VINF_SUCCESS;
1144 break;
1145 }
1146 }
1147
1148 do /* goto avoidance break-loop. */
1149 {
1150 if (fSendToGuest)
1151 {
1152 if (modeGet() == VBOX_DRAG_AND_DROP_MODE_OFF)
1153 {
1154 /* Tell the host that a wrong drag'n drop mode is set. */
1155 rc = VERR_ACCESS_DENIED;
1156 break;
1157 }
1158
1159 if (m_clientMap.empty()) /* At least one client on the guest connected? */
1160 {
1161 /*
1162 * Tell the host that the guest does not support drag'n drop.
1163 * This might happen due to not installed Guest Additions or
1164 * not running VBoxTray/VBoxClient.
1165 */
1166 rc = VERR_NOT_SUPPORTED;
1167 break;
1168 }
1169
1170 rc = m_pManager->AddMsg(u32Function, cParms, paParms, true /* fAppend */);
1171 if (RT_FAILURE(rc))
1172 {
1173 AssertMsgFailed(("Adding new message of type=%RU32 failed with rc=%Rrc\n", u32Function, rc));
1174 break;
1175 }
1176
1177 /* Any clients in our queue ready for processing the next command? */
1178 if (m_clientQueue.empty())
1179 {
1180 LogFlowFunc(("All clients (%zu) busy -- delaying execution\n", m_clientMap.size()));
1181 break;
1182 }
1183
1184 uint32_t uClientNext = m_clientQueue.front();
1185 DnDClientMap::iterator itClientNext = m_clientMap.find(uClientNext);
1186 Assert(itClientNext != m_clientMap.end());
1187
1188 DragAndDropClient *pClient = itClientNext->second;
1189 AssertPtr(pClient);
1190
1191 /*
1192 * Check if this was a request for getting the next host
1193 * message. If so, return the message ID and the parameter
1194 * count. The message itself has to be queued.
1195 */
1196 uint32_t uMsgClient = pClient->GetMsgType();
1197
1198 uint32_t uMsgNext = 0;
1199 uint32_t cParmsNext = 0;
1200 int rcNext = m_pManager->GetNextMsgInfo(&uMsgNext, &cParmsNext);
1201
1202 LogFlowFunc(("uMsgClient=%RU32, uMsgNext=%RU32, cParmsNext=%RU32, rcNext=%Rrc\n",
1203 uMsgClient, uMsgNext, cParmsNext, rcNext));
1204
1205 if (RT_SUCCESS(rcNext))
1206 {
1207 if (uMsgClient == GUEST_DND_FN_GET_NEXT_HOST_MSG)
1208 {
1209 rc = pClient->SetDeferredMsgInfo(uMsgNext, cParmsNext);
1210
1211 /* Note: Report the current rc back to the guest. */
1212 pClient->CompleteDeferred(rc);
1213 }
1214 /*
1215 * Does the message the client is waiting for match the message
1216 * next in the queue? Process it right away then.
1217 */
1218 else if (uMsgClient == uMsgNext)
1219 {
1220 rc = m_pManager->GetNextMsg(u32Function, cParms, paParms);
1221
1222 /* Note: Report the current rc back to the guest. */
1223 pClient->CompleteDeferred(rc);
1224 }
1225 else /* Should not happen; cancel the operation on the guest. */
1226 {
1227 LogFunc(("Client ID=%RU32 in wrong state with uMsg=%RU32 (next message in queue: %RU32), cancelling\n",
1228 pClient->GetClientID(), uMsgClient, uMsgNext));
1229
1230 pClient->CompleteDeferred(VERR_CANCELLED);
1231 }
1232
1233 m_clientQueue.pop_front();
1234 }
1235
1236 } /* fSendToGuest */
1237
1238 } while (0); /* To use breaks. */
1239
1240 LogFlowFuncLeaveRC(rc);
1241 return rc;
1242}
1243
1244DECLCALLBACK(int) DragAndDropService::progressCallback(uint32_t uStatus, uint32_t uPercentage, int rc, void *pvUser)
1245{
1246 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1247
1248 DragAndDropService *pSelf = static_cast<DragAndDropService *>(pvUser);
1249 AssertPtr(pSelf);
1250
1251 if (pSelf->m_SvcCtx.pfnHostCallback)
1252 {
1253 LogFlowFunc(("GUEST_DND_FN_HG_EVT_PROGRESS: uStatus=%RU32, uPercentage=%RU32, rc=%Rrc\n",
1254 uStatus, uPercentage, rc));
1255
1256 VBOXDNDCBHGEVTPROGRESSDATA data;
1257 data.hdr.uMagic = CB_MAGIC_DND_HG_EVT_PROGRESS;
1258 data.uPercentage = RT_MIN(uPercentage, 100);
1259 data.uStatus = uStatus;
1260 data.rc = rc; /** @todo uin32_t vs. int. */
1261
1262 return pSelf->m_SvcCtx.pfnHostCallback(pSelf->m_SvcCtx.pvHostData,
1263 GUEST_DND_FN_HG_EVT_PROGRESS,
1264 &data, sizeof(data));
1265 }
1266
1267 return VINF_SUCCESS;
1268}
1269
1270/**
1271 * @copydoc FNVBOXHGCMSVCLOAD
1272 */
1273extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *pTable)
1274{
1275 return DragAndDropService::svcLoad(pTable);
1276}
1277
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