VirtualBox

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

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

scm copyright and license note update

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

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