VirtualBox

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

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

HGCM / DnD: Removed the protocol version from the generic HGCM client implementation and integrated it into the DnD host service instead (for keeping backwards compatibility).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 45.8 KB
Line 
1/* $Id: VBoxDragAndDropSvc.cpp 85714 2020-08-12 12:40:56Z 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_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_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_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_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_CONNECT:
434 RT_FALL_THROUGH();
435 /* New since VBox 6.1.x. */
436 case GUEST_DND_REPORT_FEATURES:
437 RT_FALL_THROUGH();
438 /* New since VBox 6.1.x. */
439 case GUEST_DND_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_HG_ACK_OP:
451 case GUEST_DND_HG_REQ_DATA:
452 case GUEST_DND_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_GH_ACK_PENDING:
463 case GUEST_DND_GH_SND_DATA_HDR:
464 case GUEST_DND_GH_SND_DATA:
465 case GUEST_DND_GH_SND_DIR:
466 case GUEST_DND_GH_SND_FILE_HDR:
467 case GUEST_DND_GH_SND_FILE_DATA:
468 case GUEST_DND_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_GET_NEXT_HOST_MSG and
550 * HOST_DND_GH_REQ_PENDING, which led this service returning
551 * VERR_INVALID_PARAMETER when the guest wanted to actually
552 * handle HOST_DND_GH_REQ_PENDING.
553 */
554 case GUEST_DND_GET_NEXT_HOST_MSG:
555 {
556 LogFlowFunc(("GUEST_DND_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_CONNECT:
602 {
603 LogFlowFunc(("GUEST_DND_CONNECT\n"));
604
605 ASSERT_GUEST_BREAK(cParms >= 2);
606
607 VBOXDNDCBCONNECTMSGDATA data;
608 RT_ZERO(data);
609
610 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.hdr.uContextID); \
611 ASSERT_GUEST_RC_BREAK(rc);
612 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.uProtocol);
613 ASSERT_GUEST_RC_BREAK(rc);
614 rc = HGCMSvcGetU32(&paParms[idxParm], &data.uFlags);
615 ASSERT_GUEST_RC_BREAK(rc);
616
617 unsigned uProtocolVer = 3; /* The protocol version we're going to use. */
618
619 /* Make sure we're only setting a protocl version we're supporting on the host. */
620 if (data.uProtocol > uProtocolVer)
621 data.uProtocol = uProtocolVer;
622
623 pClient->uProtocolVerDeprecated = data.uProtocol;
624
625 /* Return the highest protocol version we're supporting. */
626 AssertBreak(idxParm);
627 ASSERT_GUEST_BREAK(idxParm);
628 paParms[idxParm - 1].u.uint32 = data.uProtocol;
629
630 LogFlowFunc(("Client %RU32 is now using protocol v%RU32\n",
631 pClient->GetClientID(), pClient->uProtocolVerDeprecated));
632
633 DO_HOST_CALLBACK();
634 break;
635 }
636 case GUEST_DND_REPORT_FEATURES:
637 {
638 LogFlowFunc(("GUEST_DND_REPORT_FEATURES\n"));
639 rc = clientReportFeatures(pClient, callHandle, cParms, paParms);
640 break;
641 }
642 case GUEST_DND_QUERY_FEATURES:
643 {
644 LogFlowFunc(("GUEST_DND_QUERY_FEATURES"));
645 rc = clientQueryFeatures(pClient, callHandle, cParms, paParms);
646 break;
647 }
648 case GUEST_DND_HG_ACK_OP:
649 {
650 LogFlowFunc(("GUEST_DND_HG_ACK_OP\n"));
651
652 ASSERT_GUEST_BREAK(cParms >= 2);
653
654 VBOXDNDCBHGACKOPDATA data;
655 RT_ZERO(data);
656 data.hdr.uMagic = CB_MAGIC_DND_HG_ACK_OP;
657
658 GET_CONTEXT_ID_PARM0();
659 rc = HGCMSvcGetU32(&paParms[idxParm], &data.uAction); /* Get drop action. */
660 ASSERT_GUEST_RC_BREAK(rc);
661
662 DO_HOST_CALLBACK();
663 break;
664 }
665 case GUEST_DND_HG_REQ_DATA:
666 {
667 LogFlowFunc(("GUEST_DND_HG_REQ_DATA\n"));
668
669 VBOXDNDCBHGREQDATADATA data;
670 RT_ZERO(data);
671 data.hdr.uMagic = CB_MAGIC_DND_HG_REQ_DATA;
672
673 switch (pClient->uProtocolVerDeprecated)
674 {
675 case 3:
676 {
677 ASSERT_GUEST_BREAK(cParms == 3);
678 GET_CONTEXT_ID_PARM0();
679 rc = HGCMSvcGetPv(&paParms[idxParm++], (void **)&data.pszFormat, &data.cbFormat);
680 ASSERT_GUEST_RC_BREAK(rc);
681 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm], data.cbFormat);
682 break;
683 }
684
685 case 2:
686 RT_FALL_THROUGH();
687 default:
688 {
689 ASSERT_GUEST_BREAK(cParms == 1);
690 rc = HGCMSvcGetPv(&paParms[idxParm], (void**)&data.pszFormat, &data.cbFormat);
691 ASSERT_GUEST_RC_BREAK(rc);
692 break;
693 }
694 }
695
696 DO_HOST_CALLBACK();
697 break;
698 }
699 case GUEST_DND_HG_EVT_PROGRESS:
700 {
701 LogFlowFunc(("GUEST_DND_HG_EVT_PROGRESS\n"));
702
703 ASSERT_GUEST_BREAK(cParms >= 3);
704
705 VBOXDNDCBHGEVTPROGRESSDATA data;
706 RT_ZERO(data);
707 data.hdr.uMagic = CB_MAGIC_DND_HG_EVT_PROGRESS;
708
709 GET_CONTEXT_ID_PARM0();
710 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.uStatus);
711 ASSERT_GUEST_RC_BREAK(rc);
712 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.uPercentage);
713 ASSERT_GUEST_RC_BREAK(rc);
714 rc = HGCMSvcGetU32(&paParms[idxParm], &data.rc);
715 ASSERT_GUEST_RC_BREAK(rc);
716
717 DO_HOST_CALLBACK();
718 break;
719 }
720#ifdef VBOX_WITH_DRAG_AND_DROP_GH
721 case GUEST_DND_GH_ACK_PENDING:
722 {
723 LogFlowFunc(("GUEST_DND_GH_ACK_PENDING\n"));
724
725 VBOXDNDCBGHACKPENDINGDATA data;
726 RT_ZERO(data);
727 data.hdr.uMagic = CB_MAGIC_DND_GH_ACK_PENDING;
728
729 switch (pClient->uProtocolVerDeprecated)
730 {
731 case 3:
732 {
733 ASSERT_GUEST_BREAK(cParms == 5);
734 GET_CONTEXT_ID_PARM0();
735 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.uDefAction);
736 ASSERT_GUEST_RC_BREAK(rc);
737 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.uAllActions);
738 ASSERT_GUEST_RC_BREAK(rc);
739 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.pszFormat, &data.cbFormat);
740 ASSERT_GUEST_RC_BREAK(rc);
741 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm], data.cbFormat);
742 break;
743 }
744
745 case 2:
746 default:
747 {
748 ASSERT_GUEST_BREAK(cParms == 3);
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 break;
756 }
757 }
758
759 DO_HOST_CALLBACK();
760 break;
761 }
762 /* New since protocol v3. */
763 case GUEST_DND_GH_SND_DATA_HDR:
764 {
765 LogFlowFunc(("GUEST_DND_GH_SND_DATA_HDR\n"));
766
767 ASSERT_GUEST_BREAK(cParms == 12);
768
769 VBOXDNDCBSNDDATAHDRDATA data;
770 RT_ZERO(data);
771 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_DATA_HDR;
772
773 GET_CONTEXT_ID_PARM0();
774 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.data.uFlags);
775 ASSERT_GUEST_RC_BREAK(rc);
776 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.data.uScreenId);
777 ASSERT_GUEST_RC_BREAK(rc);
778 rc = HGCMSvcGetU64(&paParms[idxParm++], &data.data.cbTotal);
779 ASSERT_GUEST_RC_BREAK(rc);
780 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.data.cbMeta);
781 ASSERT_GUEST_RC_BREAK(rc);
782 ASSERT_GUEST_BREAK(data.data.cbMeta <= data.data.cbTotal);
783 rc = HGCMSvcGetPv(&paParms[idxParm++], &data.data.pvMetaFmt, &data.data.cbMetaFmt);
784 ASSERT_GUEST_RC_BREAK(rc);
785 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm++], data.data.cbMetaFmt);
786 rc = HGCMSvcGetU64(&paParms[idxParm++], &data.data.cObjects);
787 ASSERT_GUEST_RC_BREAK(rc);
788 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.data.enmCompression);
789 ASSERT_GUEST_RC_BREAK(rc);
790 rc = HGCMSvcGetU32(&paParms[idxParm++], (uint32_t *)&data.data.enmChecksumType);
791 ASSERT_GUEST_RC_BREAK(rc);
792 rc = HGCMSvcGetPv(&paParms[idxParm++], &data.data.pvChecksum, &data.data.cbChecksum);
793 ASSERT_GUEST_RC_BREAK(rc);
794 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm], data.data.cbChecksum);
795
796 DO_HOST_CALLBACK();
797 break;
798 }
799 case GUEST_DND_GH_SND_DATA:
800 {
801 LogFlowFunc(("GUEST_DND_GH_SND_DATA\n"));
802
803 switch (pClient->uProtocolVerDeprecated)
804 {
805 case 3:
806 {
807 ASSERT_GUEST_BREAK(cParms == 5);
808
809 VBOXDNDCBSNDDATADATA data;
810 RT_ZERO(data);
811 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_DATA;
812
813 GET_CONTEXT_ID_PARM0();
814 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.data.u.v3.pvData, &data.data.u.v3.cbData);
815 ASSERT_GUEST_RC_BREAK(rc);
816 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm++], data.data.u.v3.cbData);
817 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.data.u.v3.pvChecksum, &data.data.u.v3.cbChecksum);
818 ASSERT_GUEST_RC_BREAK(rc);
819 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm], data.data.u.v3.cbChecksum);
820
821 DO_HOST_CALLBACK();
822 break;
823 }
824
825 case 2:
826 default:
827 {
828 ASSERT_GUEST_BREAK(cParms == 2);
829
830 VBOXDNDCBSNDDATADATA data;
831 RT_ZERO(data);
832 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_DATA;
833
834 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.data.u.v1.pvData, &data.data.u.v1.cbData);
835 ASSERT_GUEST_RC_BREAK(rc);
836 rc = HGCMSvcGetU32(&paParms[idxParm], &data.data.u.v1.cbTotalSize);
837 ASSERT_GUEST_RC_BREAK(rc);
838
839 DO_HOST_CALLBACK();
840 break;
841 }
842 }
843 break;
844 }
845 case GUEST_DND_GH_SND_DIR:
846 {
847 LogFlowFunc(("GUEST_DND_GH_SND_DIR\n"));
848
849 ASSERT_GUEST_BREAK(cParms >= 3);
850
851 VBOXDNDCBSNDDIRDATA data;
852 RT_ZERO(data);
853 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_DIR;
854
855 GET_CONTEXT_ID_PARM0();
856 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.pszPath, &data.cbPath);
857 ASSERT_GUEST_RC_BREAK(rc);
858 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm++], data.cbPath);
859 rc = HGCMSvcGetU32(&paParms[idxParm], &data.fMode);
860 ASSERT_GUEST_RC_BREAK(rc);
861
862 DO_HOST_CALLBACK();
863 break;
864 }
865 /* New since protocol v2 (>= VBox 5.0). */
866 case GUEST_DND_GH_SND_FILE_HDR:
867 {
868 LogFlowFunc(("GUEST_DND_GH_SND_FILE_HDR\n"));
869
870 ASSERT_GUEST_BREAK(cParms == 6);
871
872 VBOXDNDCBSNDFILEHDRDATA data;
873 RT_ZERO(data);
874 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_FILE_HDR;
875
876 GET_CONTEXT_ID_PARM0();
877 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.pszFilePath, &data.cbFilePath);
878 ASSERT_GUEST_RC_BREAK(rc);
879 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm++], data.cbFilePath);
880 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.fFlags);
881 ASSERT_GUEST_RC_BREAK(rc);
882 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.fMode);
883 ASSERT_GUEST_RC_BREAK(rc);
884 rc = HGCMSvcGetU64(&paParms[idxParm], &data.cbSize);
885 ASSERT_GUEST_RC_BREAK(rc);
886
887 DO_HOST_CALLBACK();
888 break;
889 }
890 case GUEST_DND_GH_SND_FILE_DATA:
891 {
892 LogFlowFunc(("GUEST_DND_GH_SND_FILE_DATA\n"));
893
894 switch (pClient->uProtocolVerDeprecated)
895 {
896 /* Protocol v3 adds (optional) checksums. */
897 case 3:
898 {
899 ASSERT_GUEST_BREAK(cParms == 5);
900
901 VBOXDNDCBSNDFILEDATADATA data;
902 RT_ZERO(data);
903 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_FILE_DATA;
904
905 GET_CONTEXT_ID_PARM0();
906 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.pvData, &data.cbData);
907 ASSERT_GUEST_RC_BREAK(rc);
908 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm++], data.cbData);
909 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.u.v3.pvChecksum, &data.u.v3.cbChecksum);
910 ASSERT_GUEST_RC_BREAK(rc);
911 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm], data.u.v3.cbChecksum);
912
913 DO_HOST_CALLBACK();
914 break;
915 }
916 /* Protocol v2 only sends the next data chunks to reduce traffic. */
917 case 2:
918 {
919 ASSERT_GUEST_BREAK(cParms == 3);
920
921 VBOXDNDCBSNDFILEDATADATA data;
922 RT_ZERO(data);
923 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_FILE_DATA;
924
925 GET_CONTEXT_ID_PARM0();
926 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.pvData, &data.cbData);
927 ASSERT_GUEST_RC_BREAK(rc);
928 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm], data.cbData);
929
930 DO_HOST_CALLBACK();
931 break;
932 }
933 /* Protocol v1 sends the file path and attributes for every file chunk (!). */
934 default:
935 {
936 ASSERT_GUEST_BREAK(cParms == 5);
937
938 VBOXDNDCBSNDFILEDATADATA data;
939 RT_ZERO(data);
940 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_FILE_DATA;
941
942 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.u.v1.pszFilePath, &data.u.v1.cbFilePath);
943 ASSERT_GUEST_RC_BREAK(rc);
944 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm++], data.u.v1.cbFilePath);
945 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.pvData, &data.cbData);
946 ASSERT_GUEST_RC_BREAK(rc);
947 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm++], data.cbData);
948 rc = HGCMSvcGetU32(&paParms[idxParm], &data.u.v1.fMode);
949 ASSERT_GUEST_RC_BREAK(rc);
950
951 DO_HOST_CALLBACK();
952 break;
953 }
954 }
955 break;
956 }
957 case GUEST_DND_GH_EVT_ERROR:
958 {
959 LogFlowFunc(("GUEST_DND_GH_EVT_ERROR\n"));
960
961 ASSERT_GUEST_BREAK(cParms >= 1);
962
963 VBOXDNDCBEVTERRORDATA data;
964 RT_ZERO(data);
965 data.hdr.uMagic = CB_MAGIC_DND_GH_EVT_ERROR;
966
967 GET_CONTEXT_ID_PARM0();
968 rc = HGCMSvcGetU32(&paParms[idxParm], (uint32_t *)&data.rc);
969 ASSERT_GUEST_RC_BREAK(rc);
970
971 DO_HOST_CALLBACK();
972 break;
973 }
974#endif /* VBOX_WITH_DRAG_AND_DROP_GH */
975
976 default:
977 {
978 /* All other messages are handled by the DnD manager. */
979 rc = m_pManager->GetNextMsg(u32Function, cParms, paParms);
980 if (rc == VERR_NO_DATA) /* Manager has no new messsages? Try asking the host. */
981 {
982 if (m_SvcCtx.pfnHostCallback)
983 {
984 VBOXDNDCBHGGETNEXTHOSTMSGDATA data;
985 RT_ZERO(data);
986
987 data.hdr.uMagic = VBOX_DND_CB_MAGIC_MAKE(0 /* uFn */, 0 /* uVer */);
988
989 data.uMsg = u32Function;
990 data.cParms = cParms;
991 data.paParms = paParms;
992
993 rc = m_SvcCtx.pfnHostCallback(m_SvcCtx.pvHostData, u32Function,
994 &data, sizeof(data));
995 if (RT_SUCCESS(rc))
996 {
997 cParms = data.cParms;
998 paParms = data.paParms;
999 }
1000 else
1001 {
1002 /*
1003 * In case the guest is too fast asking for the next message
1004 * and the host did not supply it yet, just defer the client's
1005 * return until a response from the host available.
1006 */
1007 LogFlowFunc(("No new messages from the host (yet), deferring request: %Rrc\n", rc));
1008 rc = VINF_HGCM_ASYNC_EXECUTE;
1009 }
1010 }
1011 else /* No host callback in place, so drag and drop is not supported by the host. */
1012 rc = VERR_NOT_SUPPORTED;
1013 }
1014 break;
1015 }
1016 }
1017 }
1018
1019#undef VERIFY_BUFFER_SIZE_UINT32
1020
1021 /*
1022 * If async execution is requested, we didn't notify the guest yet about
1023 * completion. The client is queued into the waiters list and will be
1024 * notified as soon as a new event is available.
1025 */
1026 if (rc == VINF_HGCM_ASYNC_EXECUTE)
1027 {
1028 try
1029 {
1030 AssertPtr(pClient);
1031 pClient->SetDeferred(callHandle, u32Function, cParms, paParms);
1032 m_clientQueue.push_back(idClient);
1033 }
1034 catch (std::bad_alloc &)
1035 {
1036 rc = VERR_NO_MEMORY;
1037 /* Don't report to guest. */
1038 }
1039 }
1040 else if (pClient)
1041 pClient->Complete(callHandle, rc);
1042 else
1043 {
1044 AssertMsgFailed(("Guest call failed with %Rrc\n", rc));
1045 rc = VERR_NOT_IMPLEMENTED;
1046 }
1047
1048 LogFlowFunc(("Returning rc=%Rrc\n", rc));
1049}
1050
1051int DragAndDropService::hostCall(uint32_t u32Function,
1052 uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT
1053{
1054 LogFlowFunc(("u32Function=%RU32, cParms=%RU32, cClients=%zu, cQueue=%zu\n",
1055 u32Function, cParms, m_clientMap.size(), m_clientQueue.size()));
1056
1057 int rc;
1058 bool fSendToGuest = false; /* Whether to send the message down to the guest side or not. */
1059
1060 switch (u32Function)
1061 {
1062 case HOST_DND_SET_MODE:
1063 {
1064 if (cParms != 1)
1065 rc = VERR_INVALID_PARAMETER;
1066 else if (paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT)
1067 rc = VERR_INVALID_PARAMETER;
1068 else
1069 rc = modeSet(paParms[0].u.uint32);
1070 break;
1071 }
1072
1073 case HOST_DND_CANCEL:
1074 {
1075 LogFlowFunc(("Cancelling all waiting clients ...\n"));
1076
1077 /* Reset the message queue as the host cancelled the whole operation. */
1078 m_pManager->Reset();
1079
1080 rc = m_pManager->AddMsg(u32Function, cParms, paParms, true /* fAppend */);
1081 if (RT_FAILURE(rc))
1082 {
1083 AssertMsgFailed(("Adding new message of type=%RU32 failed with rc=%Rrc\n", u32Function, rc));
1084 break;
1085 }
1086
1087 /*
1088 * Wake up all deferred clients and tell them to process
1089 * the cancelling message next.
1090 */
1091 DnDClientQueue::iterator itQueue = m_clientQueue.begin();
1092 while (itQueue != m_clientQueue.end())
1093 {
1094 DnDClientMap::iterator itClient = m_clientMap.find(*itQueue);
1095 Assert(itClient != m_clientMap.end());
1096
1097 DragAndDropClient *pClient = itClient->second;
1098 AssertPtr(pClient);
1099
1100 int rc2 = pClient->SetDeferredMsgInfo(HOST_DND_CANCEL,
1101 /* Protocol v3+ also contains the context ID. */
1102 pClient->uProtocolVerDeprecated >= 3 ? 1 : 0);
1103 pClient->CompleteDeferred(rc2);
1104
1105 m_clientQueue.erase(itQueue);
1106 itQueue = m_clientQueue.begin();
1107 }
1108
1109 Assert(m_clientQueue.empty());
1110
1111 /* Tell the host that everything went well. */
1112 rc = VINF_SUCCESS;
1113 break;
1114 }
1115
1116 case HOST_DND_HG_EVT_ENTER:
1117 {
1118 /* Reset the message queue as a new DnD operation just began. */
1119 m_pManager->Reset();
1120
1121 fSendToGuest = true;
1122 rc = VINF_SUCCESS;
1123 break;
1124 }
1125
1126 default:
1127 {
1128 fSendToGuest = true;
1129 rc = VINF_SUCCESS;
1130 break;
1131 }
1132 }
1133
1134 do /* goto avoidance break-loop. */
1135 {
1136 if (fSendToGuest)
1137 {
1138 if (modeGet() == VBOX_DRAG_AND_DROP_MODE_OFF)
1139 {
1140 /* Tell the host that a wrong drag'n drop mode is set. */
1141 rc = VERR_ACCESS_DENIED;
1142 break;
1143 }
1144
1145 if (m_clientMap.empty()) /* At least one client on the guest connected? */
1146 {
1147 /*
1148 * Tell the host that the guest does not support drag'n drop.
1149 * This might happen due to not installed Guest Additions or
1150 * not running VBoxTray/VBoxClient.
1151 */
1152 rc = VERR_NOT_SUPPORTED;
1153 break;
1154 }
1155
1156 rc = m_pManager->AddMsg(u32Function, cParms, paParms, true /* fAppend */);
1157 if (RT_FAILURE(rc))
1158 {
1159 AssertMsgFailed(("Adding new message of type=%RU32 failed with rc=%Rrc\n", u32Function, rc));
1160 break;
1161 }
1162
1163 /* Any clients in our queue ready for processing the next command? */
1164 if (m_clientQueue.empty())
1165 {
1166 LogFlowFunc(("All clients (%zu) busy -- delaying execution\n", m_clientMap.size()));
1167 break;
1168 }
1169
1170 uint32_t uClientNext = m_clientQueue.front();
1171 DnDClientMap::iterator itClientNext = m_clientMap.find(uClientNext);
1172 Assert(itClientNext != m_clientMap.end());
1173
1174 DragAndDropClient *pClient = itClientNext->second;
1175 AssertPtr(pClient);
1176
1177 /*
1178 * Check if this was a request for getting the next host
1179 * message. If so, return the message ID and the parameter
1180 * count. The message itself has to be queued.
1181 */
1182 uint32_t uMsgClient = pClient->GetMsgType();
1183
1184 uint32_t uMsgNext = 0;
1185 uint32_t cParmsNext = 0;
1186 int rcNext = m_pManager->GetNextMsgInfo(&uMsgNext, &cParmsNext);
1187
1188 LogFlowFunc(("uMsgClient=%RU32, uMsgNext=%RU32, cParmsNext=%RU32, rcNext=%Rrc\n",
1189 uMsgClient, uMsgNext, cParmsNext, rcNext));
1190
1191 if (RT_SUCCESS(rcNext))
1192 {
1193 if (uMsgClient == GUEST_DND_GET_NEXT_HOST_MSG)
1194 {
1195 rc = pClient->SetDeferredMsgInfo(uMsgNext, cParmsNext);
1196
1197 /* Note: Report the current rc back to the guest. */
1198 pClient->CompleteDeferred(rc);
1199 }
1200 /*
1201 * Does the message the client is waiting for match the message
1202 * next in the queue? Process it right away then.
1203 */
1204 else if (uMsgClient == uMsgNext)
1205 {
1206 rc = m_pManager->GetNextMsg(u32Function, cParms, paParms);
1207
1208 /* Note: Report the current rc back to the guest. */
1209 pClient->CompleteDeferred(rc);
1210 }
1211 else /* Should not happen; cancel the operation on the guest. */
1212 {
1213 LogFunc(("Client ID=%RU32 in wrong state with uMsg=%RU32 (next message in queue: %RU32), cancelling\n",
1214 pClient->GetClientID(), uMsgClient, uMsgNext));
1215
1216 pClient->CompleteDeferred(VERR_CANCELLED);
1217 }
1218
1219 m_clientQueue.pop_front();
1220 }
1221
1222 } /* fSendToGuest */
1223
1224 } while (0); /* To use breaks. */
1225
1226 LogFlowFuncLeaveRC(rc);
1227 return rc;
1228}
1229
1230DECLCALLBACK(int) DragAndDropService::progressCallback(uint32_t uStatus, uint32_t uPercentage, int rc, void *pvUser)
1231{
1232 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1233
1234 DragAndDropService *pSelf = static_cast<DragAndDropService *>(pvUser);
1235 AssertPtr(pSelf);
1236
1237 if (pSelf->m_SvcCtx.pfnHostCallback)
1238 {
1239 LogFlowFunc(("GUEST_DND_HG_EVT_PROGRESS: uStatus=%RU32, uPercentage=%RU32, rc=%Rrc\n",
1240 uStatus, uPercentage, rc));
1241
1242 VBOXDNDCBHGEVTPROGRESSDATA data;
1243 data.hdr.uMagic = CB_MAGIC_DND_HG_EVT_PROGRESS;
1244 data.uPercentage = RT_MIN(uPercentage, 100);
1245 data.uStatus = uStatus;
1246 data.rc = rc; /** @todo uin32_t vs. int. */
1247
1248 return pSelf->m_SvcCtx.pfnHostCallback(pSelf->m_SvcCtx.pvHostData,
1249 GUEST_DND_HG_EVT_PROGRESS,
1250 &data, sizeof(data));
1251 }
1252
1253 return VINF_SUCCESS;
1254}
1255
1256/**
1257 * @copydoc FNVBOXHGCMSVCLOAD
1258 */
1259extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *pTable)
1260{
1261 return DragAndDropService::svcLoad(pTable);
1262}
1263
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