VirtualBox

source: vbox/trunk/src/VBox/HostServices/DragAndDrop/service.cpp@ 57753

Last change on this file since 57753 was 57753, checked in by vboxsync, 9 years ago

IPRT: Renamed RTPROC_FLAGS_NO_PROFILE to RTPROC_FLAGS_PROFILE.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.0 KB
Line 
1/* $Id: service.cpp 57753 2015-09-15 11:15:21Z vboxsync $ */
2/** @file
3 * Drag and Drop Service.
4 */
5
6/*
7 * Copyright (C) 2011-2015 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_guest_control Guest Control HGCM Service
19 *
20 * This service acts as a proxy for handling and buffering host command requests
21 * and clients on the guest. It tries to be as transparent as possible to let
22 * the guest (client) and host side do their protocol handling as desired.
23 *
24 * The following terms are used:
25 * - Host: A host process (e.g. VBoxManage or another tool utilizing the Main API)
26 * which wants to control something on the guest.
27 * - Client: A client (e.g. VBoxService) running inside the guest OS waiting for
28 * new host commands to perform. There can be multiple clients connected
29 * to a service. A client is represented by its HGCM client ID.
30 * - Context ID: An (almost) unique ID automatically generated on the host (Main API)
31 * to not only distinguish clients but individual requests. Because
32 * the host does not know anything about connected clients it needs
33 * an indicator which it can refer to later. This context ID gets
34 * internally bound by the service to a client which actually processes
35 * the command in order to have a relationship between client<->context ID(s).
36 *
37 * The host can trigger commands which get buffered by the service (with full HGCM
38 * parameter info). As soon as a client connects (or is ready to do some new work)
39 * it gets a buffered host command to process it. This command then will be immediately
40 * removed from the command list. If there are ready clients but no new commands to be
41 * processed, these clients will be set into a deferred state (that is being blocked
42 * to return until a new command is available).
43 *
44 * If a client needs to inform the host that something happened, it can send a
45 * message to a low level HGCM callback registered in Main. This callback contains
46 * the actual data as well as the context ID to let the host do the next necessary
47 * steps for this context. This context ID makes it possible to wait for an event
48 * inside the host's Main API function (like starting a process on the guest and
49 * wait for getting its PID returned by the client) as well as cancelling blocking
50 * host calls in order the client terminated/crashed (HGCM detects disconnected
51 * clients and reports it to this service's callback).
52 */
53
54
55/*********************************************************************************************************************************
56* Header Files *
57*********************************************************************************************************************************/
58#ifdef LOG_GROUP
59 #undef LOG_GROUP
60#endif
61#define LOG_GROUP LOG_GROUP_GUEST_DND
62
63#include <map>
64
65#include "dndmanager.h"
66
67
68/*********************************************************************************************************************************
69* Service class declaration *
70*********************************************************************************************************************************/
71
72/** Map holding pointers to HGCM clients. Key is the (unique) HGCM client ID. */
73typedef std::map<uint32_t, HGCM::Client*> DnDClientMap;
74
75/**
76 * Specialized drag & drop service class.
77 */
78class DragAndDropService : public HGCM::AbstractService<DragAndDropService>
79{
80public:
81
82 explicit DragAndDropService(PVBOXHGCMSVCHELPERS pHelpers)
83 : HGCM::AbstractService<DragAndDropService>(pHelpers)
84 , m_pManager(NULL) {}
85
86protected:
87
88 int init(VBOXHGCMSVCFNTABLE *pTable);
89 int uninit(void);
90 int clientConnect(uint32_t u32ClientID, void *pvClient);
91 int clientDisconnect(uint32_t u32ClientID, void *pvClient);
92 void guestCall(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, void *pvClient, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
93 int hostCall(uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
94
95 int modeSet(uint32_t u32Mode);
96 inline uint32_t modeGet() { return m_u32Mode; };
97
98protected:
99
100 static DECLCALLBACK(int) progressCallback(uint32_t uStatus, uint32_t uPercentage, int rc, void *pvUser);
101
102protected:
103
104 DnDManager *m_pManager;
105 /** Map of all connected clients. */
106 DnDClientMap m_clientMap;
107 /** List of all clients which are queued up (deferred return) and ready
108 * to process new commands. */
109 RTCList<HGCM::Client*> m_clientQueue;
110 uint32_t m_u32Mode;
111};
112
113
114/*********************************************************************************************************************************
115* Service class implementation *
116*********************************************************************************************************************************/
117
118int DragAndDropService::init(VBOXHGCMSVCFNTABLE *pTable)
119{
120 /* Register functions. */
121 pTable->pfnHostCall = svcHostCall;
122 pTable->pfnSaveState = NULL; /* The service is stateless, so the normal */
123 pTable->pfnLoadState = NULL; /* construction done before restoring suffices */
124 pTable->pfnRegisterExtension = svcRegisterExtension;
125
126 /* Drag'n drop mode is disabled by default. */
127 modeSet(VBOX_DRAG_AND_DROP_MODE_OFF);
128
129 int rc = VINF_SUCCESS;
130
131 try
132 {
133 m_pManager = new DnDManager(&DragAndDropService::progressCallback, this);
134 }
135 catch(std::bad_alloc &)
136 {
137 rc = VERR_NO_MEMORY;
138 }
139
140 LogFlowFuncLeaveRC(rc);
141 return rc;
142}
143
144int DragAndDropService::uninit(void)
145{
146 if (m_pManager)
147 {
148 delete m_pManager;
149 m_pManager = NULL;
150 }
151
152 return VINF_SUCCESS;
153}
154
155int DragAndDropService::clientConnect(uint32_t u32ClientID, void *pvClient)
156{
157 if (m_clientMap.size() >= UINT8_MAX) /* Don't allow too much clients at the same time. */
158 {
159 AssertMsgFailed(("Maximum number of clients reached\n"));
160 return VERR_BUFFER_OVERFLOW;
161 }
162
163 int rc = VINF_SUCCESS;
164
165 /*
166 * Add client to our client map.
167 */
168 if (m_clientMap.find(u32ClientID) != m_clientMap.end())
169 rc = VERR_ALREADY_EXISTS;
170
171 if (RT_SUCCESS(rc))
172 {
173 try
174 {
175 m_clientMap[u32ClientID] = new HGCM::Client(u32ClientID);
176 }
177 catch(std::bad_alloc &)
178 {
179 rc = VERR_NO_MEMORY;
180 }
181
182 if (RT_SUCCESS(rc))
183 {
184 /*
185 * Clear the message queue as soon as a new clients connect
186 * to ensure that every client has the same state.
187 */
188 if (m_pManager)
189 m_pManager->clear();
190 }
191 }
192
193 LogFlowFunc(("Client %RU32 connected, rc=%Rrc\n", u32ClientID, rc));
194 return rc;
195}
196
197int DragAndDropService::clientDisconnect(uint32_t u32ClientID, void *pvClient)
198{
199 /* Client not found? Bail out early. */
200 DnDClientMap::iterator itClient = m_clientMap.find(u32ClientID);
201 if (itClient == m_clientMap.end())
202 return VERR_NOT_FOUND;
203
204 /*
205 * Remove from waiters queue.
206 */
207 for (size_t i = 0; i < m_clientQueue.size(); i++)
208 {
209 HGCM::Client *pClient = m_clientQueue.at(i);
210 if (pClient->clientId() == u32ClientID)
211 {
212 if (m_pHelpers)
213 m_pHelpers->pfnCallComplete(pClient->handle(), VERR_INTERRUPTED);
214
215 m_clientQueue.removeAt(i);
216 delete pClient;
217
218 break;
219 }
220 }
221
222 /*
223 * Remove from client map and deallocate.
224 */
225 AssertPtr(itClient->second);
226 delete itClient->second;
227
228 m_clientMap.erase(itClient);
229
230 LogFlowFunc(("Client %RU32 disconnected\n", u32ClientID));
231 return VINF_SUCCESS;
232}
233
234int DragAndDropService::modeSet(uint32_t u32Mode)
235{
236 /** @todo Validate mode. */
237 switch (u32Mode)
238 {
239 case VBOX_DRAG_AND_DROP_MODE_OFF:
240 case VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST:
241 case VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST:
242 case VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL:
243 m_u32Mode = u32Mode;
244 break;
245
246 default:
247 m_u32Mode = VBOX_DRAG_AND_DROP_MODE_OFF;
248 break;
249 }
250
251 return VINF_SUCCESS;
252}
253
254void DragAndDropService::guestCall(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID,
255 void *pvClient, uint32_t u32Function,
256 uint32_t cParms, VBOXHGCMSVCPARM paParms[])
257{
258 LogFlowFunc(("u32ClientID=%RU32, u32Function=%RU32, cParms=%RU32\n",
259 u32ClientID, u32Function, cParms));
260
261 /* Check if we've the right mode set. */
262 int rc = VERR_ACCESS_DENIED; /* Play safe. */
263 switch (u32Function)
264 {
265 case DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG:
266 {
267 if (modeGet() != VBOX_DRAG_AND_DROP_MODE_OFF)
268 {
269 rc = VINF_SUCCESS;
270 }
271 else
272 {
273 LogFlowFunc(("DnD disabled, deferring request\n"));
274 rc = VINF_HGCM_ASYNC_EXECUTE;
275 }
276 break;
277 }
278
279 /* Note: New since protocol version 2. */
280 case DragAndDropSvc::GUEST_DND_CONNECT:
281 {
282 /*
283 * Never block the initial connect call, as the clients do this when
284 * initializing and might get stuck if drag and drop is set to "disabled" at
285 * that time.
286 */
287 rc = VINF_SUCCESS;
288 break;
289 }
290 case DragAndDropSvc::GUEST_DND_HG_ACK_OP:
291 /* Fall through is intentional. */
292 case DragAndDropSvc::GUEST_DND_HG_REQ_DATA:
293 /* Fall through is intentional. */
294 case DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS:
295 {
296 if ( modeGet() == VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
297 || modeGet() == VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST)
298 {
299 rc = VINF_SUCCESS;
300 }
301 else
302 LogFlowFunc(("Host -> Guest DnD mode disabled, ignoring request\n"));
303 break;
304 }
305
306 case DragAndDropSvc::GUEST_DND_GH_ACK_PENDING:
307 case DragAndDropSvc::GUEST_DND_GH_SND_DATA:
308 case DragAndDropSvc::GUEST_DND_GH_SND_DIR:
309 case DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR:
310 case DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA:
311 case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR:
312 {
313#ifdef VBOX_WITH_DRAG_AND_DROP_GH
314 if ( modeGet() == VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
315 || modeGet() == VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST)
316 {
317 rc = VINF_SUCCESS;
318 }
319 else
320#endif
321 LogFlowFunc(("Guest -> Host DnD mode disabled, ignoring request\n"));
322 break;
323 }
324
325 default:
326 /* Reach through to DnD manager. */
327 rc = VINF_SUCCESS;
328 break;
329 }
330
331#ifdef DEBUG_andy
332 LogFlowFunc(("Mode (%RU32) check rc=%Rrc\n", modeGet(), rc));
333#endif
334
335#define DO_HOST_CALLBACK(); \
336 if ( RT_SUCCESS(rc) \
337 && m_pfnHostCallback) \
338 { \
339 rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data)); \
340 }
341
342 if (rc == VINF_SUCCESS) /* Note: rc might be VINF_HGCM_ASYNC_EXECUTE! */
343 {
344 DnDClientMap::iterator itClient = m_clientMap.find(u32ClientID);
345 Assert(itClient != m_clientMap.end());
346
347 HGCM::Client *pClient = itClient->second;
348 AssertPtr(pClient);
349
350 switch (u32Function)
351 {
352 /*
353 * Note: Older VBox versions with enabled DnD guest->host support (< 5.0)
354 * used the same message ID (300) for GUEST_DND_GET_NEXT_HOST_MSG and
355 * HOST_DND_GH_REQ_PENDING, which led this service returning
356 * VERR_INVALID_PARAMETER when the guest wanted to actually
357 * handle HOST_DND_GH_REQ_PENDING.
358 */
359 case DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG:
360 {
361 LogFlowFunc(("GUEST_DND_GET_NEXT_HOST_MSG\n"));
362 if ( cParms != 3
363 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* message */
364 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* parameter count */
365 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* blocking */)
366 {
367 rc = VERR_INVALID_PARAMETER;
368 }
369 else
370 {
371 rc = m_pManager->nextMessageInfo(&paParms[0].u.uint32 /* uMsg */, &paParms[1].u.uint32 /* cParms */);
372 if (RT_FAILURE(rc)) /* No queued messages available? */
373 {
374 if (m_pfnHostCallback) /* Try asking the host. */
375 {
376 DragAndDropSvc::VBOXDNDCBHGGETNEXTHOSTMSG data;
377 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG;
378 rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
379 if (RT_SUCCESS(rc))
380 {
381 paParms[0].u.uint32 = data.uMsg; /* uMsg */
382 paParms[1].u.uint32 = data.cParms; /* cParms */
383 /* Note: paParms[2] was set by the guest as blocking flag. */
384 }
385 }
386 else /* No host callback in place, so drag and drop is not supported by the host. */
387 rc = VERR_NOT_SUPPORTED;
388
389 if (RT_FAILURE(rc))
390 rc = m_pManager->nextMessage(u32Function, cParms, paParms);
391
392 /* Some error occurred or no (new) messages available? */
393 if (RT_FAILURE(rc))
394 {
395 if (paParms[2].u.uint32) /* Blocking flag set? */
396 {
397 /* Defer client returning. */
398 rc = VINF_HGCM_ASYNC_EXECUTE;
399 }
400
401 LogFlowFunc(("Message queue is empty, returning %Rrc to guest\n", rc));
402 }
403 }
404 }
405 break;
406 }
407 case DragAndDropSvc::GUEST_DND_CONNECT:
408 {
409 LogFlowFunc(("GUEST_DND_CONNECT\n"));
410 if ( cParms != 2
411 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* protocol version */
412 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* additional connection flags */)
413 rc = VERR_INVALID_PARAMETER;
414 else
415 {
416 uint32_t uProtocol;
417 rc = paParms[0].getUInt32(&uProtocol); /* Get protocol version. */
418 if (RT_SUCCESS(rc))
419 rc = pClient->setProtocol(uProtocol);
420 if (RT_SUCCESS(rc))
421 {
422 /** @todo Handle connection flags (paParms[1]). */
423 }
424
425 /* Note: Does not reach the host; the client's protocol version
426 * is only kept in this service. */
427 }
428 break;
429 }
430 case DragAndDropSvc::GUEST_DND_HG_ACK_OP:
431 {
432 LogFlowFunc(("GUEST_DND_HG_ACK_OP\n"));
433 if ( cParms != 1
434 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* action */)
435 rc = VERR_INVALID_PARAMETER;
436 else
437 {
438 DragAndDropSvc::VBOXDNDCBHGACKOPDATA data;
439 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_ACK_OP;
440 rc = paParms[0].getUInt32(&data.uAction); /* Get drop action. */
441 DO_HOST_CALLBACK();
442 }
443 break;
444 }
445 case DragAndDropSvc::GUEST_DND_HG_REQ_DATA:
446 {
447 LogFlowFunc(("GUEST_DND_HG_REQ_DATA\n"));
448 if ( cParms != 1
449 || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* format */)
450 rc = VERR_INVALID_PARAMETER;
451 else
452 {
453 DragAndDropSvc::VBOXDNDCBHGREQDATADATA data;
454 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_REQ_DATA;
455 rc = paParms[0].getPointer((void**)&data.pszFormat, &data.cbFormat);
456 DO_HOST_CALLBACK();
457 }
458 break;
459 }
460 case DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS:
461 {
462 LogFlowFunc(("GUEST_DND_HG_EVT_PROGRESS\n"));
463 if ( cParms != 3
464 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* status */
465 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* percent */
466 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* rc */)
467 rc = VERR_INVALID_PARAMETER;
468 else
469 {
470 DragAndDropSvc::VBOXDNDCBHGEVTPROGRESSDATA data;
471 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_EVT_PROGRESS;
472 rc = paParms[0].getUInt32(&data.uStatus);
473 if (RT_SUCCESS(rc))
474 rc = paParms[1].getUInt32(&data.uPercentage);
475 if (RT_SUCCESS(rc))
476 rc = paParms[2].getUInt32(&data.rc);
477 DO_HOST_CALLBACK();
478 }
479 break;
480 }
481#ifdef VBOX_WITH_DRAG_AND_DROP_GH
482 case DragAndDropSvc::GUEST_DND_GH_ACK_PENDING:
483 {
484 LogFlowFunc(("GUEST_DND_GH_ACK_PENDING\n"));
485 if ( cParms != 3
486 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* defaction */
487 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* alloctions */
488 || paParms[2].type != VBOX_HGCM_SVC_PARM_PTR /* format */)
489 rc = VERR_INVALID_PARAMETER;
490 else
491 {
492 DragAndDropSvc::VBOXDNDCBGHACKPENDINGDATA data;
493 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_ACK_PENDING;
494 rc = paParms[0].getUInt32(&data.uDefAction);
495 if (RT_SUCCESS(rc))
496 rc = paParms[1].getUInt32(&data.uAllActions);
497 if (RT_SUCCESS(rc))
498 rc = paParms[2].getPointer((void**)&data.pszFormat, &data.cbFormat);
499 DO_HOST_CALLBACK();
500 }
501 break;
502 }
503 case DragAndDropSvc::GUEST_DND_GH_SND_DATA:
504 {
505 LogFlowFunc(("GUEST_DND_GH_SND_DATA\n"));
506 if ( cParms != 2
507 || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* data */
508 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* size */)
509 rc = VERR_INVALID_PARAMETER;
510 else
511 {
512 DragAndDropSvc::VBOXDNDCBSNDDATADATA data;
513 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_DATA;
514 rc = paParms[0].getPointer((void**)&data.pvData, &data.cbData);
515 if (RT_SUCCESS(rc))
516 rc = paParms[1].getUInt32(&data.cbTotalSize);
517 DO_HOST_CALLBACK();
518 }
519 break;
520 }
521 case DragAndDropSvc::GUEST_DND_GH_SND_DIR:
522 {
523 LogFlowFunc(("GUEST_DND_GH_SND_DIR\n"));
524 if ( cParms != 3
525 || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* path */
526 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* path length */
527 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* creation mode */)
528 rc = VERR_INVALID_PARAMETER;
529 else
530 {
531 DragAndDropSvc::VBOXDNDCBSNDDIRDATA data;
532 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_DIR;
533 uint32_t cTmp;
534 rc = paParms[0].getPointer((void**)&data.pszPath, &cTmp);
535 if (RT_SUCCESS(rc))
536 rc = paParms[1].getUInt32(&data.cbPath);
537 if (RT_SUCCESS(rc))
538 rc = paParms[2].getUInt32(&data.fMode);
539
540 LogFlowFunc(("pszPath=%s, cbPath=%RU32, fMode=0x%x\n", data.pszPath, data.cbPath, data.fMode));
541 DO_HOST_CALLBACK();
542 }
543 break;
544 }
545 /* Note: Since protocol v2 (>= VBox 5.0). */
546 case DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR:
547 {
548 LogFlowFunc(("GUEST_DND_GH_SND_FILE_HDR\n"));
549 if ( cParms != 6
550 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* context ID */
551 || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* file path */
552 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* file path length */
553 || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* flags */
554 || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* file mode */
555 || paParms[5].type != VBOX_HGCM_SVC_PARM_64BIT /* file size */)
556 rc = VERR_INVALID_PARAMETER;
557 else
558 {
559 DragAndDropSvc::VBOXDNDCBSNDFILEHDRDATA data;
560 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE_HDR;
561 uint32_t cTmp;
562 /* paParms[0] is context ID; unused yet. */
563 rc = paParms[1].getPointer((void**)&data.pszFilePath, &cTmp);
564 if (RT_SUCCESS(rc))
565 rc = paParms[2].getUInt32(&data.cbFilePath);
566 if (RT_SUCCESS(rc))
567 rc = paParms[3].getUInt32(&data.fFlags);
568 if (RT_SUCCESS(rc))
569 rc = paParms[4].getUInt32(&data.fMode);
570 if (RT_SUCCESS(rc))
571 rc = paParms[5].getUInt64(&data.cbSize);
572
573 LogFlowFunc(("pszPath=%s, cbPath=%RU32, fMode=0x%x, cbSize=%RU64\n",
574 data.pszFilePath, data.cbFilePath, data.fMode, data.cbSize));
575 DO_HOST_CALLBACK();
576 }
577 break;
578 }
579 case DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA:
580 {
581 LogFlowFunc(("GUEST_DND_GH_SND_FILE_DATA\n"));
582
583 switch (pClient->protocol())
584 {
585 case 2: /* Protocol version 2 only sends the next data chunks to reduce traffic. */
586 {
587 if ( cParms != 3
588 /* paParms[0] is context ID; unused yet. */
589 || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* file data */
590 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* file data length */)
591 {
592 rc = VERR_INVALID_PARAMETER;
593 }
594 else
595 {
596 DragAndDropSvc::VBOXDNDCBSNDFILEDATADATA data;
597 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE_DATA;
598 /* paParms[0] is context ID; unused yet. */
599 rc = paParms[1].getPointer((void**)&data.pvData, &data.cbData);
600 if (RT_SUCCESS(rc))
601 rc = paParms[2].getUInt32(&data.cbData);
602
603 LogFlowFunc(("cbData=%RU32, pvData=0x%p\n", data.cbData, data.pvData));
604 DO_HOST_CALLBACK();
605 }
606 break;
607 }
608 default:
609 {
610 if ( cParms != 5
611 || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* file path */
612 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* file path length */
613 || paParms[2].type != VBOX_HGCM_SVC_PARM_PTR /* file data */
614 || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* file data length */
615 || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* creation mode */)
616 {
617 rc = VERR_INVALID_PARAMETER;
618 }
619 else
620 {
621 DragAndDropSvc::VBOXDNDCBSNDFILEDATADATA data;
622 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE_DATA;
623 uint32_t cTmp;
624 rc = paParms[0].getPointer((void**)&data.u.v1.pszFilePath, &cTmp);
625 if (RT_SUCCESS(rc))
626 rc = paParms[1].getUInt32(&data.u.v1.cbFilePath);
627 if (RT_SUCCESS(rc))
628 rc = paParms[2].getPointer((void**)&data.pvData, &cTmp);
629 if (RT_SUCCESS(rc))
630 rc = paParms[3].getUInt32(&data.cbData);
631 if (RT_SUCCESS(rc))
632 rc = paParms[4].getUInt32(&data.u.v1.fMode);
633
634 LogFlowFunc(("pszFilePath=%s, cbData=%RU32, pvData=0x%p, fMode=0x%x\n",
635 data.u.v1.pszFilePath, data.cbData, data.pvData, data.u.v1.fMode));
636 DO_HOST_CALLBACK();
637 }
638 break;
639 }
640 }
641 break;
642 }
643 case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR:
644 {
645 LogFlowFunc(("GUEST_DND_GH_EVT_ERROR\n"));
646 if ( cParms != 1
647 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* rc */)
648 rc = VERR_INVALID_PARAMETER;
649 else
650 {
651 DragAndDropSvc::VBOXDNDCBEVTERRORDATA data;
652 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_EVT_ERROR;
653
654 uint32_t rcOp;
655 rc = paParms[0].getUInt32(&rcOp);
656 if (RT_SUCCESS(rc))
657 data.rc = rcOp;
658
659 DO_HOST_CALLBACK();
660 }
661 break;
662 }
663#endif /* VBOX_WITH_DRAG_AND_DROP_GH */
664 default:
665 {
666 /* All other messages are handled by the DnD manager. */
667 rc = m_pManager->nextMessage(u32Function, cParms, paParms);
668 if (rc == VERR_NO_DATA) /* Manager has no new messsages? Try asking the host. */
669 {
670 if (m_pfnHostCallback)
671 {
672 DragAndDropSvc::VBOXDNDCBHGGETNEXTHOSTMSGDATA data;
673 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG_DATA;
674 data.uMsg = u32Function;
675 data.cParms = cParms;
676 data.paParms = paParms;
677
678 rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
679 if (RT_SUCCESS(rc))
680 {
681 cParms = data.cParms;
682 paParms = data.paParms;
683 }
684 }
685 else /* No host callback in place, so drag and drop is not supported by the host. */
686 rc = VERR_NOT_SUPPORTED;
687 }
688 break;
689 }
690 }
691 }
692
693#undef DO_HOST_CALLBACK
694
695 /*
696 * If async execution is requested, we didn't notify the guest yet about
697 * completion. The client is queued into the waiters list and will be
698 * notified as soon as a new event is available.
699 */
700 if (rc == VINF_HGCM_ASYNC_EXECUTE)
701 {
702 try
703 {
704 LogFlowFunc(("Deferring guest call completion of client ID=%RU32\n", u32ClientID));
705 m_clientQueue.append(new HGCM::Client(u32ClientID, callHandle,
706 u32Function, cParms, paParms));
707 }
708 catch (std::bad_alloc)
709 {
710 rc = VERR_NO_MEMORY;
711 /* Don't report to guest. */
712 }
713 }
714 else if (m_pHelpers)
715 {
716 /* Complete call on guest side. */
717 m_pHelpers->pfnCallComplete(callHandle, rc);
718 }
719 else
720 rc = VERR_NOT_IMPLEMENTED;
721
722 LogFlowFunc(("Returning rc=%Rrc\n", rc));
723}
724
725int DragAndDropService::hostCall(uint32_t u32Function,
726 uint32_t cParms, VBOXHGCMSVCPARM paParms[])
727{
728 LogFlowFunc(("u32Function=%RU32, cParms=%RU32, cClients=%zu, cQueue=%zu\n",
729 u32Function, cParms, m_clientMap.size(), m_clientQueue.size()));
730
731 int rc;
732 if (u32Function == DragAndDropSvc::HOST_DND_SET_MODE)
733 {
734 if (cParms != 1)
735 rc = VERR_INVALID_PARAMETER;
736 else if (paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT)
737 rc = VERR_INVALID_PARAMETER;
738 else
739 rc = modeSet(paParms[0].u.uint32);
740 }
741 else if (modeGet() != VBOX_DRAG_AND_DROP_MODE_OFF)
742 {
743 if (m_clientMap.size()) /* At least one client on the guest connected? */
744 {
745 rc = m_pManager->addMessage(u32Function, cParms, paParms, true /* fAppend */);
746 if (RT_SUCCESS(rc))
747 {
748 if (m_clientQueue.size()) /* Any clients in our queue ready for processing the next command? */
749 {
750 HGCM::Client *pClient = m_clientQueue.first();
751 AssertPtr(pClient);
752
753 /*
754 * Check if this was a request for getting the next host
755 * message. If so, return the message ID and the parameter
756 * count. The message itself has to be queued.
757 */
758 uint32_t uMsg = pClient->message();
759 if (uMsg == DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG)
760 {
761 LogFlowFunc(("Client %RU32 is waiting for next host msg\n", pClient->clientId()));
762
763 uint32_t uMsg1;
764 uint32_t cParms1;
765 rc = m_pManager->nextMessageInfo(&uMsg1, &cParms1);
766 if (RT_SUCCESS(rc))
767 {
768 pClient->addMessageInfo(uMsg1, cParms1);
769 if ( m_pHelpers
770 && m_pHelpers->pfnCallComplete)
771 {
772 m_pHelpers->pfnCallComplete(pClient->handle(), rc);
773 }
774
775 m_clientQueue.removeFirst();
776
777 delete pClient;
778 pClient = NULL;
779 }
780 else
781 AssertMsgFailed(("m_pManager::nextMessageInfo failed with rc=%Rrc\n", rc));
782 }
783 else
784 AssertMsgFailed(("Client ID=%RU32 in wrong state with uMsg=%RU32\n",
785 pClient->clientId(), uMsg));
786 }
787 else
788 LogFlowFunc(("All clients busy; delaying execution\n"));
789 }
790 else
791 AssertMsgFailed(("Adding new message of type=%RU32 failed with rc=%Rrc\n",
792 u32Function, rc));
793 }
794 else
795 {
796 /*
797 * Tell the host that the guest does not support drag'n drop.
798 * This might happen due to not installed Guest Additions or
799 * not running VBoxTray/VBoxClient.
800 */
801 rc = VERR_NOT_SUPPORTED;
802 }
803 }
804 else
805 {
806 /* Tell the host that a wrong drag'n drop mode is set. */
807 rc = VERR_ACCESS_DENIED;
808 }
809
810 LogFlowFuncLeaveRC(rc);
811 return rc;
812}
813
814DECLCALLBACK(int) DragAndDropService::progressCallback(uint32_t uStatus, uint32_t uPercentage, int rc, void *pvUser)
815{
816 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
817
818 DragAndDropService *pSelf = static_cast<DragAndDropService *>(pvUser);
819 AssertPtr(pSelf);
820
821 if (pSelf->m_pfnHostCallback)
822 {
823 LogFlowFunc(("GUEST_DND_HG_EVT_PROGRESS: uStatus=%RU32, uPercentage=%RU32, rc=%Rrc\n",
824 uStatus, uPercentage, rc));
825
826 DragAndDropSvc::VBOXDNDCBHGEVTPROGRESSDATA data;
827 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_EVT_PROGRESS;
828 data.uPercentage = RT_MIN(uPercentage, 100);
829 data.uStatus = uStatus;
830 data.rc = rc; /** @todo uin32_t vs. int. */
831
832 return pSelf->m_pfnHostCallback(pSelf->m_pvHostData,
833 DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS,
834 &data, sizeof(data));
835 }
836
837 return VINF_SUCCESS;
838}
839
840/**
841 * @copydoc VBOXHGCMSVCLOAD
842 */
843extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *pTable)
844{
845 return DragAndDropService::svcLoad(pTable);
846}
847
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