VirtualBox

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

Last change on this file since 93075 was 90238, checked in by vboxsync, 3 years ago

HGCM,HostServices: Extended VBOXHGCMSVCFNTABLE with client and call limits. Tried to pick reasonable values for all services. bugref:9379

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