VirtualBox

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

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

DnD/HostService: Guest reboot / shutdown fixes.

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