VirtualBox

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

最後變更 在這個檔案從97731是 97731,由 vboxsync 提交於 2 年 前

DnD/Host service: Added DumpQueue() for debug builds, and also make use of DnDGuestMsgToStr() + DnDHostMsgToStr().

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette