VirtualBox

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

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

DnD: Termination fixes / clarification.

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