VirtualBox

source: vbox/trunk/src/VBox/HostServices/GuestControl/VBoxGuestControlSvc.cpp@ 92783

Last change on this file since 92783 was 90805, checked in by vboxsync, 3 years ago

HostServices: More VALID_PTR -> RT_VALID_PTR/AssertPtr.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 98.2 KB
Line 
1/* $Id: VBoxGuestControlSvc.cpp 90805 2021-08-23 19:09:17Z vboxsync $ */
2/** @file
3 * Guest Control Service: Controlling the guest.
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_guest_control Guest Control HGCM Service
19 *
20 * This service acts as a proxy for handling and buffering host message 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 messages to perform. There can be multiple clients connected
29 * to this service. A client is represented by its unique 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 message in order to have a relationship between client<->context ID(s).
36 *
37 * The host can trigger messages 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 message to process it. This message then will be immediately
40 * removed from the message list. If there are ready clients but no new messages to be
41 * processed, these clients will be set into a deferred state (that is being blocked
42 * to return until a new host message 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 * Starting at VBox 4.2 the context ID itself consists of a session ID, an object
54 * ID (for example a process or file ID) and a count. This is necessary to not break
55 * compatibility between older hosts and to manage guest session on the host.
56 */
57
58
59/*********************************************************************************************************************************
60* Header Files *
61*********************************************************************************************************************************/
62#define LOG_GROUP LOG_GROUP_GUEST_CONTROL
63#include <VBox/HostServices/GuestControlSvc.h>
64#include <VBox/GuestHost/GuestControl.h> /** @todo r=bird: Why two headers??? */
65
66#include <VBox/err.h>
67#include <VBox/log.h>
68#include <VBox/AssertGuest.h>
69#include <VBox/VMMDev.h>
70#include <VBox/vmm/ssm.h>
71#include <iprt/assert.h>
72#include <iprt/cpp/autores.h>
73#include <iprt/cpp/utils.h>
74#include <iprt/mem.h>
75#include <iprt/list.h>
76#include <iprt/req.h>
77#include <iprt/string.h>
78#include <iprt/thread.h>
79#include <iprt/time.h>
80
81#include <map>
82#include <new> /* for std::nothrow*/
83
84
85using namespace guestControl;
86
87
88/**
89 * Structure for maintaining a request.
90 */
91typedef struct ClientRequest
92{
93 /** The call handle */
94 VBOXHGCMCALLHANDLE mHandle;
95 /** Number of parameters */
96 uint32_t mNumParms;
97 /** The call parameters */
98 VBOXHGCMSVCPARM *mParms;
99 /** The default constructor. */
100 ClientRequest(void)
101 : mHandle(0), mNumParms(0), mParms(NULL)
102 {}
103} ClientRequest;
104
105/**
106 * Structure for holding a buffered host message which has
107 * not been processed yet.
108 */
109typedef struct HostMsg
110{
111 /** Entry on the ClientState::m_HostMsgList list. */
112 RTLISTNODE m_ListEntry;
113 union
114 {
115 /** The top two twomost bits are exploited for message destination.
116 * See VBOX_GUESTCTRL_DST_XXX. */
117 uint64_t m_idContextAndDst;
118 /** The context ID this message belongs to (extracted from the first parameter). */
119 uint32_t m_idContext;
120 };
121 /** Dynamic structure for holding the HGCM parms */
122 uint32_t mType;
123 /** Number of HGCM parameters. */
124 uint32_t mParmCount;
125 /** Array of HGCM parameters. */
126 PVBOXHGCMSVCPARM mpParms;
127 /** Set if we detected the message skipping hack from r121400. */
128 bool m_f60BetaHackInPlay;
129
130 HostMsg()
131 : m_idContextAndDst(0)
132 , mType(UINT32_MAX)
133 , mParmCount(0)
134 , mpParms(NULL)
135 , m_f60BetaHackInPlay(false)
136 {
137 RTListInit(&m_ListEntry);
138 }
139
140 /**
141 * Releases the host message, properly deleting it if no further references.
142 */
143 void Delete(void)
144 {
145 LogFlowThisFunc(("[Msg %RU32 (%s)] destroying\n", mType, GstCtrlHostMsgtoStr((eHostMsg)mType)));
146 if (mpParms)
147 {
148 for (uint32_t i = 0; i < mParmCount; i++)
149 if (mpParms[i].type == VBOX_HGCM_SVC_PARM_PTR)
150 {
151 RTMemFree(mpParms[i].u.pointer.addr);
152 mpParms[i].u.pointer.addr = NULL;
153 }
154 RTMemFree(mpParms);
155 mpParms = NULL;
156 }
157 mParmCount = 0;
158 delete this;
159 }
160
161
162 /**
163 * Initializes the message.
164 *
165 * The specified parameters are copied and any buffers referenced by it
166 * duplicated as well.
167 *
168 * @returns VBox status code.
169 * @param idMsg The host message number, eHostMsg.
170 * @param cParms Number of parameters in the HGCM request.
171 * @param paParms Array of parameters.
172 */
173 int Init(uint32_t idMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
174 {
175 LogFlowThisFunc(("[Msg %RU32 (%s)] Allocating cParms=%RU32, paParms=%p\n",
176 idMsg, GstCtrlHostMsgtoStr((eHostMsg)idMsg), cParms, paParms));
177 Assert(mpParms == NULL);
178 Assert(mParmCount == 0);
179 Assert(RTListIsEmpty(&m_ListEntry));
180
181 /*
182 * Fend of bad stuff.
183 */
184 AssertReturn(cParms > 0, VERR_WRONG_PARAMETER_COUNT); /* At least one parameter (context ID) must be present. */
185 AssertReturn(cParms < VMMDEV_MAX_HGCM_PARMS, VERR_WRONG_PARAMETER_COUNT);
186 AssertPtrReturn(paParms, VERR_INVALID_POINTER);
187
188 /*
189 * The first parameter is the context ID and the message destination mask.
190 */
191 if (paParms[0].type == VBOX_HGCM_SVC_PARM_64BIT)
192 {
193 m_idContextAndDst = paParms[0].u.uint64;
194 AssertReturn(m_idContextAndDst & VBOX_GUESTCTRL_DST_BOTH, VERR_INTERNAL_ERROR_3);
195 }
196 else if (paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT)
197 {
198 AssertMsgFailed(("idMsg=%u %s - caller must set dst!\n", idMsg, GstCtrlHostMsgtoStr((eHostMsg)idMsg)));
199 m_idContextAndDst = paParms[0].u.uint32 | VBOX_GUESTCTRL_DST_BOTH;
200 }
201 else
202 AssertFailedReturn(VERR_WRONG_PARAMETER_TYPE);
203
204 /*
205 * Just make a copy of the parameters and any buffers.
206 */
207 mType = idMsg;
208 mParmCount = cParms;
209 mpParms = (VBOXHGCMSVCPARM *)RTMemAllocZ(sizeof(VBOXHGCMSVCPARM) * mParmCount);
210 AssertReturn(mpParms, VERR_NO_MEMORY);
211
212 for (uint32_t i = 0; i < cParms; i++)
213 {
214 mpParms[i].type = paParms[i].type;
215 switch (paParms[i].type)
216 {
217 case VBOX_HGCM_SVC_PARM_32BIT:
218 mpParms[i].u.uint32 = paParms[i].u.uint32;
219 break;
220
221 case VBOX_HGCM_SVC_PARM_64BIT:
222 mpParms[i].u.uint64 = paParms[i].u.uint64;
223 break;
224
225 case VBOX_HGCM_SVC_PARM_PTR:
226 mpParms[i].u.pointer.size = paParms[i].u.pointer.size;
227 if (mpParms[i].u.pointer.size > 0)
228 {
229 mpParms[i].u.pointer.addr = RTMemDup(paParms[i].u.pointer.addr, mpParms[i].u.pointer.size);
230 AssertReturn(mpParms[i].u.pointer.addr, VERR_NO_MEMORY);
231 }
232 /* else: structure is zeroed by allocator. */
233 break;
234
235 default:
236 AssertMsgFailedReturn(("idMsg=%u (%s) parameter #%u: type=%u\n",
237 idMsg, GstCtrlHostMsgtoStr((eHostMsg)idMsg), i, paParms[i].type),
238 VERR_WRONG_PARAMETER_TYPE);
239 }
240 }
241
242 /*
243 * Morph the first parameter back to 32-bit.
244 */
245 mpParms[0].type = VBOX_HGCM_SVC_PARM_32BIT;
246 mpParms[0].u.uint32 = (uint32_t)paParms[0].u.uint64;
247
248 return VINF_SUCCESS;
249 }
250
251
252 /**
253 * Sets the GUEST_MSG_PEEK_WAIT GUEST_MSG_PEEK_NOWAIT return parameters.
254 *
255 * @param paDstParms The peek parameter vector.
256 * @param cDstParms The number of peek parameters (at least two).
257 * @remarks ASSUMES the parameters has been cleared by clientMsgPeek.
258 */
259 inline void setPeekReturn(PVBOXHGCMSVCPARM paDstParms, uint32_t cDstParms)
260 {
261 Assert(cDstParms >= 2);
262 if (paDstParms[0].type == VBOX_HGCM_SVC_PARM_32BIT)
263 paDstParms[0].u.uint32 = mType;
264 else
265 paDstParms[0].u.uint64 = mType;
266 paDstParms[1].u.uint32 = mParmCount;
267
268 uint32_t i = RT_MIN(cDstParms, mParmCount + 2);
269 while (i-- > 2)
270 switch (mpParms[i - 2].type)
271 {
272 case VBOX_HGCM_SVC_PARM_32BIT: paDstParms[i].u.uint32 = ~(uint32_t)sizeof(uint32_t); break;
273 case VBOX_HGCM_SVC_PARM_64BIT: paDstParms[i].u.uint32 = ~(uint32_t)sizeof(uint64_t); break;
274 case VBOX_HGCM_SVC_PARM_PTR: paDstParms[i].u.uint32 = mpParms[i - 2].u.pointer.size; break;
275 }
276 }
277
278
279 /** @name Support for old-style (GUEST_MSG_WAIT) operation.
280 * @{
281 */
282
283 /**
284 * Worker for Assign() that opies data from the buffered HGCM request to the
285 * current HGCM request.
286 *
287 * @returns VBox status code.
288 * @param paDstParms Array of parameters of HGCM request to fill the data into.
289 * @param cDstParms Number of parameters the HGCM request can handle.
290 */
291 int CopyTo(VBOXHGCMSVCPARM paDstParms[], uint32_t cDstParms) const
292 {
293 LogFlowThisFunc(("[Msg %RU32] mParmCount=%RU32, m_idContext=%RU32 (Session %RU32)\n",
294 mType, mParmCount, m_idContext, VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(m_idContext)));
295
296 int rc = VINF_SUCCESS;
297 if (cDstParms != mParmCount)
298 {
299 LogFlowFunc(("Parameter count does not match (got %RU32, expected %RU32)\n",
300 cDstParms, mParmCount));
301 rc = VERR_INVALID_PARAMETER;
302 }
303
304 if (RT_SUCCESS(rc))
305 {
306 for (uint32_t i = 0; i < mParmCount; i++)
307 {
308 if (paDstParms[i].type != mpParms[i].type)
309 {
310 LogFunc(("Parameter %RU32 type mismatch (got %RU32, expected %RU32)\n", i, paDstParms[i].type, mpParms[i].type));
311 rc = VERR_INVALID_PARAMETER;
312 }
313 else
314 {
315 switch (mpParms[i].type)
316 {
317 case VBOX_HGCM_SVC_PARM_32BIT:
318#ifdef DEBUG_andy
319 LogFlowFunc(("\tmpParms[%RU32] = %RU32 (uint32_t)\n",
320 i, mpParms[i].u.uint32));
321#endif
322 paDstParms[i].u.uint32 = mpParms[i].u.uint32;
323 break;
324
325 case VBOX_HGCM_SVC_PARM_64BIT:
326#ifdef DEBUG_andy
327 LogFlowFunc(("\tmpParms[%RU32] = %RU64 (uint64_t)\n",
328 i, mpParms[i].u.uint64));
329#endif
330 paDstParms[i].u.uint64 = mpParms[i].u.uint64;
331 break;
332
333 case VBOX_HGCM_SVC_PARM_PTR:
334 {
335#ifdef DEBUG_andy
336 LogFlowFunc(("\tmpParms[%RU32] = %p (ptr), size = %RU32\n",
337 i, mpParms[i].u.pointer.addr, mpParms[i].u.pointer.size));
338#endif
339 if (!mpParms[i].u.pointer.size)
340 continue; /* Only copy buffer if there actually is something to copy. */
341
342 if (!paDstParms[i].u.pointer.addr)
343 rc = VERR_INVALID_PARAMETER;
344 else if (paDstParms[i].u.pointer.size < mpParms[i].u.pointer.size)
345 rc = VERR_BUFFER_OVERFLOW;
346 else
347 memcpy(paDstParms[i].u.pointer.addr,
348 mpParms[i].u.pointer.addr,
349 mpParms[i].u.pointer.size);
350 break;
351 }
352
353 default:
354 LogFunc(("Parameter %RU32 of type %RU32 is not supported yet\n", i, mpParms[i].type));
355 rc = VERR_NOT_SUPPORTED;
356 break;
357 }
358 }
359
360 if (RT_FAILURE(rc))
361 {
362 LogFunc(("Parameter %RU32 invalid (%Rrc), refusing\n", i, rc));
363 break;
364 }
365 }
366 }
367
368 LogFlowFunc(("Returned with rc=%Rrc\n", rc));
369 return rc;
370 }
371
372 int Assign(const ClientRequest *pReq)
373 {
374 AssertPtrReturn(pReq, VERR_INVALID_POINTER);
375
376 int rc;
377
378 LogFlowThisFunc(("[Msg %RU32] mParmCount=%RU32, mpParms=%p\n", mType, mParmCount, mpParms));
379
380 /* Does the current host message need more parameter space which
381 * the client does not provide yet? */
382 if (mParmCount > pReq->mNumParms)
383 {
384 LogFlowThisFunc(("[Msg %RU32] Requires %RU32 parms, only got %RU32 from client\n",
385 mType, mParmCount, pReq->mNumParms));
386 /*
387 * So this call apparently failed because the guest wanted to peek
388 * how much parameters it has to supply in order to successfully retrieve
389 * this message. Let's tell him so!
390 */
391 rc = VERR_TOO_MUCH_DATA;
392 }
393 else
394 {
395 rc = CopyTo(pReq->mParms, pReq->mNumParms);
396
397 /*
398 * Has there been enough parameter space but the wrong parameter types
399 * were submitted -- maybe the client was just asking for the next upcoming
400 * host message?
401 *
402 * Note: To keep this compatible to older clients we return VERR_TOO_MUCH_DATA
403 * in every case.
404 */
405 if (RT_FAILURE(rc))
406 rc = VERR_TOO_MUCH_DATA;
407 }
408
409 return rc;
410 }
411
412 int Peek(const ClientRequest *pReq)
413 {
414 AssertPtrReturn(pReq, VERR_INVALID_POINTER);
415
416 LogFlowThisFunc(("[Msg %RU32] mParmCount=%RU32, mpParms=%p\n", mType, mParmCount, mpParms));
417
418 if (pReq->mNumParms >= 2)
419 {
420 HGCMSvcSetU32(&pReq->mParms[0], mType); /* Message ID */
421 HGCMSvcSetU32(&pReq->mParms[1], mParmCount); /* Required parameters for message */
422 }
423 else
424 LogFlowThisFunc(("Warning: Client has not (yet) submitted enough parameters (%RU32, must be at least 2) to at least peak for the next message\n",
425 pReq->mNumParms));
426
427 /*
428 * Always return VERR_TOO_MUCH_DATA data here to
429 * keep it compatible with older clients and to
430 * have correct accounting (mHostRc + mHostMsgTries).
431 */
432 return VERR_TOO_MUCH_DATA;
433 }
434
435 /** @} */
436} HostMsg;
437
438/**
439 * Per-client structure used for book keeping/state tracking a
440 * certain host message.
441 */
442typedef struct ClientContext
443{
444 /* Pointer to list node of this message. */
445 HostMsg *mpHostMsg;
446 /** The standard constructor. */
447 ClientContext(void) : mpHostMsg(NULL) {}
448 /** Internal constrcutor. */
449 ClientContext(HostMsg *pHostMsg) : mpHostMsg(pHostMsg) {}
450} ClientContext;
451typedef std::map< uint32_t, ClientContext > ClientContextMap;
452
453/**
454 * Structure for holding a connected guest client state.
455 */
456typedef struct ClientState
457{
458 PVBOXHGCMSVCHELPERS m_pSvcHelpers;
459 /** Host message list to process (HostMsg). */
460 RTLISTANCHOR m_HostMsgList;
461 /** The HGCM client ID. */
462 uint32_t m_idClient;
463 /** The session ID for this client, UINT32_MAX if not set or master. */
464 uint32_t m_idSession;
465 /** Set if master. */
466 bool m_fIsMaster;
467 /** Set if restored (needed for shutting legacy mode assert on non-masters). */
468 bool m_fRestored;
469
470 /** Set if we've got a pending wait cancel. */
471 bool m_fPendingCancel;
472 /** Pending client call (GUEST_MSG_PEEK_WAIT or GUEST_MSG_WAIT), zero if none pending.
473 *
474 * This means the client waits for a new host message to reply and won't return
475 * from the waiting call until a new host message is available. */
476 guestControl::eGuestMsg m_enmPendingMsg;
477 /** Pending peek/wait request details. */
478 ClientRequest m_PendingReq;
479
480
481 ClientState(void)
482 : m_pSvcHelpers(NULL)
483 , m_idClient(0)
484 , m_idSession(UINT32_MAX)
485 , m_fIsMaster(false)
486 , m_fRestored(false)
487 , m_fPendingCancel(false)
488 , m_enmPendingMsg((guestControl::eGuestMsg)0)
489 , mHostMsgRc(VINF_SUCCESS)
490 , mHostMsgTries(0)
491 , mPeekCount(0)
492 {
493 RTListInit(&m_HostMsgList);
494 }
495
496 ClientState(PVBOXHGCMSVCHELPERS pSvcHelpers, uint32_t idClient)
497 : m_pSvcHelpers(pSvcHelpers)
498 , m_idClient(idClient)
499 , m_idSession(UINT32_MAX)
500 , m_fIsMaster(false)
501 , m_fRestored(false)
502 , m_fPendingCancel(false)
503 , m_enmPendingMsg((guestControl::eGuestMsg)0)
504 , mHostMsgRc(VINF_SUCCESS)
505 , mHostMsgTries(0)
506 , mPeekCount(0)
507 {
508 RTListInit(&m_HostMsgList);
509 }
510
511 /**
512 * Used by for Service::hostProcessMessage().
513 */
514 void EnqueueMessage(HostMsg *pHostMsg)
515 {
516 AssertPtr(pHostMsg);
517 RTListAppend(&m_HostMsgList, &pHostMsg->m_ListEntry);
518 }
519
520 /**
521 * Used by for Service::hostProcessMessage().
522 *
523 * @note This wakes up both GUEST_MSG_WAIT and GUEST_MSG_PEEK_WAIT sleepers.
524 */
525 int Wakeup(void)
526 {
527 int rc = VINF_NO_CHANGE;
528
529 if (m_enmPendingMsg != 0)
530 {
531 LogFlowFunc(("[Client %RU32] Waking up ...\n", m_idClient));
532
533 rc = VINF_SUCCESS;
534
535 HostMsg *pFirstMsg = RTListGetFirstCpp(&m_HostMsgList, HostMsg, m_ListEntry);
536 if (pFirstMsg)
537 {
538 LogFlowThisFunc(("[Client %RU32] Current host message is %RU32 (CID=%#RX32, cParms=%RU32)\n",
539 m_idClient, pFirstMsg->mType, pFirstMsg->m_idContext, pFirstMsg->mParmCount));
540
541 if (m_enmPendingMsg == GUEST_MSG_PEEK_WAIT)
542 {
543 pFirstMsg->setPeekReturn(m_PendingReq.mParms, m_PendingReq.mNumParms);
544 rc = m_pSvcHelpers->pfnCallComplete(m_PendingReq.mHandle, VINF_SUCCESS);
545
546 m_PendingReq.mHandle = NULL;
547 m_PendingReq.mParms = NULL;
548 m_PendingReq.mNumParms = 0;
549 m_enmPendingMsg = (guestControl::eGuestMsg)0;
550 }
551 else if (m_enmPendingMsg == GUEST_MSG_WAIT)
552 rc = OldRun(&m_PendingReq, pFirstMsg);
553 else
554 AssertMsgFailed(("m_enmIsPending=%d\n", m_enmPendingMsg));
555 }
556 else
557 AssertMsgFailed(("Waking up client ID=%RU32 with no host message in queue is a bad idea\n", m_idClient));
558
559 return rc;
560 }
561
562 return VINF_NO_CHANGE;
563 }
564
565 /**
566 * Used by Service::call() to handle GUEST_MSG_CANCEL.
567 *
568 * @note This cancels both GUEST_MSG_WAIT and GUEST_MSG_PEEK_WAIT sleepers.
569 */
570 int CancelWaiting()
571 {
572 LogFlowFunc(("[Client %RU32] Cancelling waiting thread, isPending=%d, pendingNumParms=%RU32, m_idSession=%x\n",
573 m_idClient, m_enmPendingMsg, m_PendingReq.mNumParms, m_idSession));
574
575 /*
576 * The PEEK call is simple: At least two parameters, all set to zero before sleeping.
577 */
578 int rcComplete;
579 if (m_enmPendingMsg == GUEST_MSG_PEEK_WAIT)
580 {
581 HGCMSvcSetU32(&m_PendingReq.mParms[0], HOST_MSG_CANCEL_PENDING_WAITS);
582 rcComplete = VINF_TRY_AGAIN;
583 }
584 /*
585 * The GUEST_MSG_WAIT call is complicated, though we're generally here
586 * to wake up someone who is peeking and have two parameters. If there
587 * aren't two parameters, fail the call.
588 */
589 else if (m_enmPendingMsg != 0)
590 {
591 Assert(m_enmPendingMsg == GUEST_MSG_WAIT);
592 if (m_PendingReq.mNumParms > 0)
593 HGCMSvcSetU32(&m_PendingReq.mParms[0], HOST_MSG_CANCEL_PENDING_WAITS);
594 if (m_PendingReq.mNumParms > 1)
595 HGCMSvcSetU32(&m_PendingReq.mParms[1], 0);
596 rcComplete = m_PendingReq.mNumParms == 2 ? VINF_SUCCESS : VERR_TRY_AGAIN;
597 }
598 /*
599 * If nobody is waiting, flag the next wait call as cancelled.
600 */
601 else
602 {
603 m_fPendingCancel = true;
604 return VINF_SUCCESS;
605 }
606
607 m_pSvcHelpers->pfnCallComplete(m_PendingReq.mHandle, rcComplete);
608
609 m_PendingReq.mHandle = NULL;
610 m_PendingReq.mParms = NULL;
611 m_PendingReq.mNumParms = 0;
612 m_enmPendingMsg = (guestControl::eGuestMsg)0;
613 m_fPendingCancel = false;
614 return VINF_SUCCESS;
615 }
616
617
618 /** @name The GUEST_MSG_WAIT state and helpers.
619 *
620 * @note Don't try understand this, it is certificable!
621 *
622 * @{
623 */
624
625 /** Last (most recent) rc after handling the host message. */
626 int mHostMsgRc;
627 /** How many GUEST_MSG_WAIT calls the client has issued to retrieve one message.
628 *
629 * This is used as a heuristic to remove a message that the client appears not
630 * to be able to successfully retrieve. */
631 uint32_t mHostMsgTries;
632 /** Number of times we've peeked at a pending message.
633 *
634 * This is necessary for being compatible with older Guest Additions. In case
635 * there are messages which only have two (2) parameters and therefore would fit
636 * into the GUEST_MSG_WAIT reply immediately, we now can make sure that the
637 * client first gets back the GUEST_MSG_WAIT results first.
638 */
639 uint32_t mPeekCount;
640
641 /**
642 * Ditches the first host message and crazy GUEST_MSG_WAIT state.
643 *
644 * @note Only used by GUEST_MSG_WAIT scenarios.
645 */
646 void OldDitchFirstHostMsg()
647 {
648 HostMsg *pFirstMsg = RTListGetFirstCpp(&m_HostMsgList, HostMsg, m_ListEntry);
649 Assert(pFirstMsg);
650 RTListNodeRemove(&pFirstMsg->m_ListEntry);
651 pFirstMsg->Delete();
652
653 /* Reset state else. */
654 mHostMsgRc = VINF_SUCCESS;
655 mHostMsgTries = 0;
656 mPeekCount = 0;
657 }
658
659 /**
660 * Used by Wakeup() and OldRunCurrent().
661 *
662 * @note Only used by GUEST_MSG_WAIT scenarios.
663 */
664 int OldRun(ClientRequest const *pReq, HostMsg *pHostMsg)
665 {
666 AssertPtrReturn(pReq, VERR_INVALID_POINTER);
667 AssertPtrReturn(pHostMsg, VERR_INVALID_POINTER);
668 Assert(RTListNodeIsFirst(&m_HostMsgList, &pHostMsg->m_ListEntry));
669
670 LogFlowFunc(("[Client %RU32] pReq=%p, mHostMsgRc=%Rrc, mHostMsgTries=%RU32, mPeekCount=%RU32\n",
671 m_idClient, pReq, mHostMsgRc, mHostMsgTries, mPeekCount));
672
673 int rc = mHostMsgRc = OldSendReply(pReq, pHostMsg);
674
675 LogFlowThisFunc(("[Client %RU32] Processing host message %RU32 ended with rc=%Rrc\n",
676 m_idClient, pHostMsg->mType, mHostMsgRc));
677
678 bool fRemove = false;
679 if (RT_FAILURE(rc))
680 {
681 mHostMsgTries++;
682
683 /*
684 * If the client understood the message but supplied too little buffer space
685 * don't send this message again and drop it after 6 unsuccessful attempts.
686 *
687 * Note: Due to legacy reasons this the retry counter has to be even because on
688 * every peek there will be the actual message retrieval from the client side.
689 * To not get the actual message if the client actually only wants to peek for
690 * the next message, there needs to be two rounds per try, e.g. 3 rounds = 6 tries.
691 */
692 /** @todo Fix the mess stated above. GUEST_MSG_WAIT should be become GUEST_MSG_PEEK, *only*
693 * (and every time) returning the next upcoming host message (if any, blocking). Then
694 * it's up to the client what to do next, either peeking again or getting the actual
695 * host message via an own GUEST_ type message.
696 */
697 if ( rc == VERR_TOO_MUCH_DATA
698 || rc == VERR_CANCELLED)
699 {
700 if (mHostMsgTries == 6)
701 fRemove = true;
702 }
703 /* Client did not understand the message or something else weird happened. Try again one
704 * more time and drop it if it didn't get handled then. */
705 else if (mHostMsgTries > 1)
706 fRemove = true;
707 }
708 else
709 fRemove = true; /* Everything went fine, remove it. */
710
711 LogFlowThisFunc(("[Client %RU32] Tried host message %RU32 for %RU32 times, (last result=%Rrc, fRemove=%RTbool)\n",
712 m_idClient, pHostMsg->mType, mHostMsgTries, rc, fRemove));
713
714 if (fRemove)
715 {
716 Assert(RTListNodeIsFirst(&m_HostMsgList, &pHostMsg->m_ListEntry));
717 OldDitchFirstHostMsg();
718 }
719
720 LogFlowFunc(("[Client %RU32] Returned with rc=%Rrc\n", m_idClient, rc));
721 return rc;
722 }
723
724 /**
725 * @note Only used by GUEST_MSG_WAIT scenarios.
726 */
727 int OldRunCurrent(const ClientRequest *pReq)
728 {
729 AssertPtrReturn(pReq, VERR_INVALID_POINTER);
730
731 /*
732 * If the host message list is empty, the request must wait for one to be posted.
733 */
734 HostMsg *pFirstMsg = RTListGetFirstCpp(&m_HostMsgList, HostMsg, m_ListEntry);
735 if (!pFirstMsg)
736 {
737 if (!m_fPendingCancel)
738 {
739 /* Go to sleep. */
740 ASSERT_GUEST_RETURN(m_enmPendingMsg == 0, VERR_WRONG_ORDER);
741 m_PendingReq = *pReq;
742 m_enmPendingMsg = GUEST_MSG_WAIT;
743 LogFlowFunc(("[Client %RU32] Is now in pending mode\n", m_idClient));
744 return VINF_HGCM_ASYNC_EXECUTE;
745 }
746
747 /* Wait was cancelled. */
748 m_fPendingCancel = false;
749 if (pReq->mNumParms > 0)
750 HGCMSvcSetU32(&pReq->mParms[0], HOST_MSG_CANCEL_PENDING_WAITS);
751 if (pReq->mNumParms > 1)
752 HGCMSvcSetU32(&pReq->mParms[1], 0);
753 return pReq->mNumParms == 2 ? VINF_SUCCESS : VERR_TRY_AGAIN;
754 }
755
756 /*
757 * Return first host message.
758 */
759 return OldRun(pReq, pFirstMsg);
760 }
761
762 /**
763 * Internal worker for OldRun().
764 * @note Only used for GUEST_MSG_WAIT.
765 */
766 int OldSendReply(ClientRequest const *pReq,
767 HostMsg *pHostMsg)
768 {
769 AssertPtrReturn(pReq, VERR_INVALID_POINTER);
770 AssertPtrReturn(pHostMsg, VERR_INVALID_POINTER);
771
772 /* In case of VERR_CANCELLED. */
773 uint32_t const cSavedPeeks = mPeekCount;
774
775 int rc;
776 /* If the client is in pending mode, always send back
777 * the peek result first. */
778 if (m_enmPendingMsg)
779 {
780 Assert(m_enmPendingMsg == GUEST_MSG_WAIT);
781 rc = pHostMsg->Peek(pReq);
782 mPeekCount++;
783 }
784 else
785 {
786 /* If this is the very first peek, make sure to *always* give back the peeking answer
787 * instead of the actual message, even if this message would fit into the current
788 * connection buffer. */
789 if (!mPeekCount)
790 {
791 rc = pHostMsg->Peek(pReq);
792 mPeekCount++;
793 }
794 else
795 {
796 /* Try assigning the host message to the client and store the
797 * result code for later use. */
798 rc = pHostMsg->Assign(pReq);
799 if (RT_FAILURE(rc)) /* If something failed, let the client peek (again). */
800 {
801 rc = pHostMsg->Peek(pReq);
802 mPeekCount++;
803 }
804 else
805 mPeekCount = 0;
806 }
807 }
808
809 /* Reset pending status. */
810 m_enmPendingMsg = (guestControl::eGuestMsg)0;
811
812 /* In any case the client did something, so complete
813 * the pending call with the result we just got. */
814 AssertPtr(m_pSvcHelpers);
815 int rc2 = m_pSvcHelpers->pfnCallComplete(pReq->mHandle, rc);
816
817 /* Rollback in case the guest cancelled the call. */
818 if (rc2 == VERR_CANCELLED && RT_SUCCESS(rc))
819 {
820 mPeekCount = cSavedPeeks;
821 rc = VERR_CANCELLED;
822 }
823
824 LogFlowThisFunc(("[Client %RU32] Message %RU32 ended with %Rrc (mPeekCount=%RU32, pReq=%p)\n",
825 m_idClient, pHostMsg->mType, rc, mPeekCount, pReq));
826 return rc;
827 }
828
829 /** @} */
830} ClientState;
831typedef std::map< uint32_t, ClientState *> ClientStateMap;
832
833/**
834 * Prepared session (GUEST_SESSION_PREPARE).
835 */
836typedef struct GstCtrlPreparedSession
837{
838 /** List entry. */
839 RTLISTNODE ListEntry;
840 /** The session ID. */
841 uint32_t idSession;
842 /** The key size. */
843 uint32_t cbKey;
844 /** The key bytes. */
845 RT_FLEXIBLE_ARRAY_EXTENSION
846 uint8_t abKey[RT_FLEXIBLE_ARRAY];
847} GstCtrlPreparedSession;
848
849
850/**
851 * Class containing the shared information service functionality.
852 */
853class GstCtrlService : public RTCNonCopyable
854{
855
856private:
857
858 /** Type definition for use in callback functions. */
859 typedef GstCtrlService SELF;
860 /** HGCM helper functions. */
861 PVBOXHGCMSVCHELPERS mpHelpers;
862 /** Callback function supplied by the host for notification of updates to properties. */
863 PFNHGCMSVCEXT mpfnHostCallback;
864 /** User data pointer to be supplied to the host callback function. */
865 void *mpvHostData;
866 /** Map containing all connected clients, key is HGCM client ID. */
867 ClientStateMap m_ClientStateMap;
868 /** Session ID -> client state. */
869 ClientStateMap m_SessionIdMap;
870 /** The current master client, NULL if none. */
871 ClientState *m_pMasterClient;
872 /** The master HGCM client ID, UINT32_MAX if none. */
873 uint32_t m_idMasterClient;
874 /** Set if we're in legacy mode (pre 6.0). */
875 bool m_fLegacyMode;
876 /** Number of prepared sessions. */
877 uint32_t m_cPreparedSessions;
878 /** List of prepared session (GstCtrlPreparedSession). */
879 RTLISTANCHOR m_PreparedSessions;
880 /** Guest feature flags, VBOX_GUESTCTRL_GF_0_XXX. */
881 uint64_t m_fGuestFeatures0;
882 /** Guest feature flags, VBOX_GUESTCTRL_GF_1_XXX. */
883 uint64_t m_fGuestFeatures1;
884
885public:
886 explicit GstCtrlService(PVBOXHGCMSVCHELPERS pHelpers)
887 : mpHelpers(pHelpers)
888 , mpfnHostCallback(NULL)
889 , mpvHostData(NULL)
890 , m_pMasterClient(NULL)
891 , m_idMasterClient(UINT32_MAX)
892 , m_fLegacyMode(true)
893 , m_cPreparedSessions(0)
894 , m_fGuestFeatures0(0)
895 , m_fGuestFeatures1(0)
896 {
897 RTListInit(&m_PreparedSessions);
898 }
899
900 static DECLCALLBACK(int) svcUnload(void *pvService);
901 static DECLCALLBACK(int) svcConnect(void *pvService, uint32_t idClient, void *pvClient,
902 uint32_t fRequestor, bool fRestoring);
903 static DECLCALLBACK(int) svcDisconnect(void *pvService, uint32_t idClient, void *pvClient);
904 static DECLCALLBACK(void) svcCall(void *pvService, VBOXHGCMCALLHANDLE hCall, uint32_t idClient, void *pvClient,
905 uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[], uint64_t tsArrival);
906 static DECLCALLBACK(int) svcHostCall(void *pvService, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
907 static DECLCALLBACK(int) svcSaveState(void *pvService, uint32_t idClient, void *pvClient, PSSMHANDLE pSSM);
908 static DECLCALLBACK(int) svcLoadState(void *pvService, uint32_t idClient, void *pvClient, PSSMHANDLE pSSM, uint32_t uVersion);
909 static DECLCALLBACK(int) svcRegisterExtension(void *pvService, PFNHGCMSVCEXT pfnExtension, void *pvExtension);
910
911private:
912 int clientMakeMeMaster(ClientState *pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms);
913 int clientReportFeatures(ClientState *pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
914 int clientQueryFeatures(ClientState *pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
915 int clientMsgPeek(ClientState *pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool fWait);
916 int clientMsgGet(ClientState *pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
917 int clientMsgCancel(ClientState *pClient, uint32_t cParms);
918 int clientMsgSkip(ClientState *pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
919 int clientSessionPrepare(ClientState *pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
920 int clientSessionCancelPrepared(ClientState *pClient, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
921 int clientSessionAccept(ClientState *pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
922 int clientSessionCloseOther(ClientState *pClient, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
923 int clientToMain(ClientState *pClient, uint32_t idMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
924
925 int clientMsgOldGet(ClientState *pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
926 int clientMsgOldFilterSet(ClientState *pClient, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
927 int clientMsgOldSkip(ClientState *pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms);
928
929 int hostCallback(uint32_t idMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
930 int hostProcessMessage(uint32_t idMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
931
932 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(GstCtrlService);
933};
934
935
936/** Host feature mask for GUEST_MSG_REPORT_FEATURES/GUEST_MSG_QUERY_FEATURES. */
937static uint64_t const g_fGstCtrlHostFeatures0 = VBOX_GUESTCTRL_HF_0_NOTIFY_RDWR_OFFSET
938 | VBOX_GUESTCTRL_HF_0_PROCESS_ARGV0;
939
940
941/**
942 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnUnload,
943 * Simply deletes the GstCtrlService object}
944 */
945/*static*/ DECLCALLBACK(int)
946GstCtrlService::svcUnload(void *pvService)
947{
948 AssertLogRelReturn(RT_VALID_PTR(pvService), VERR_INVALID_PARAMETER);
949 SELF *pThis = reinterpret_cast<SELF *>(pvService);
950 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
951
952 delete pThis;
953
954 return VINF_SUCCESS;
955}
956
957
958
959/**
960 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnConnect,
961 * Initializes the state for a new client.}
962 */
963/*static*/ DECLCALLBACK(int)
964GstCtrlService::svcConnect(void *pvService, uint32_t idClient, void *pvClient, uint32_t fRequestor, bool fRestoring)
965{
966 LogFlowFunc(("[Client %RU32] Connected\n", idClient));
967
968 RT_NOREF(fRestoring, pvClient);
969 AssertLogRelReturn(RT_VALID_PTR(pvService), VERR_INVALID_PARAMETER);
970 SELF *pThis = reinterpret_cast<SELF *>(pvService);
971 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
972
973 AssertMsg(pThis->m_ClientStateMap.find(idClient) == pThis->m_ClientStateMap.end(),
974 ("Client with ID=%RU32 already connected when it should not\n", idClient));
975
976 /*
977 * Create client state.
978 */
979 ClientState *pClient = NULL;
980 try
981 {
982 pClient = new (pvClient) ClientState(pThis->mpHelpers, idClient);
983 pThis->m_ClientStateMap[idClient] = pClient;
984 }
985 catch (std::bad_alloc &)
986 {
987 if (pClient)
988 pClient->~ClientState();
989 return VERR_NO_MEMORY;
990 }
991
992 /*
993 * For legacy compatibility reasons we have to pick a master client at some
994 * point, so if the /dev/vboxguest requirements checks out we pick the first
995 * one through the door.
996 */
997/** @todo make picking the master more dynamic/flexible? */
998 if ( pThis->m_fLegacyMode
999 && pThis->m_idMasterClient == UINT32_MAX)
1000 {
1001 if ( fRequestor == VMMDEV_REQUESTOR_LEGACY
1002 || !(fRequestor & VMMDEV_REQUESTOR_USER_DEVICE))
1003 {
1004 LogFunc(("Picking %u as master for now.\n", idClient));
1005 pThis->m_pMasterClient = pClient;
1006 pThis->m_idMasterClient = idClient;
1007 pClient->m_fIsMaster = true;
1008 }
1009 }
1010
1011 return VINF_SUCCESS;
1012}
1013
1014
1015/**
1016 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnConnect,
1017 * Handles a client which disconnected.}
1018 *
1019 * This functiond does some internal cleanup as well as sends notifications to
1020 * the host so that the host can do the same (if required).
1021 */
1022/*static*/ DECLCALLBACK(int)
1023GstCtrlService::svcDisconnect(void *pvService, uint32_t idClient, void *pvClient)
1024{
1025 SELF *pThis = reinterpret_cast<SELF *>(pvService);
1026 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1027 ClientState *pClient = reinterpret_cast<ClientState *>(pvClient);
1028 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
1029 LogFlowFunc(("[Client %RU32] Disconnected (%zu clients total)\n", idClient, pThis->m_ClientStateMap.size()));
1030
1031 /*
1032 * Cancel all pending host messages, replying with GUEST_DISCONNECTED if final recipient.
1033 */
1034 HostMsg *pCurMsg, *pNextMsg;
1035 RTListForEachSafeCpp(&pClient->m_HostMsgList, pCurMsg, pNextMsg, HostMsg, m_ListEntry)
1036 {
1037 RTListNodeRemove(&pCurMsg->m_ListEntry);
1038
1039 VBOXHGCMSVCPARM Parm;
1040 HGCMSvcSetU32(&Parm, pCurMsg->m_idContext);
1041 int rc2 = pThis->hostCallback(GUEST_MSG_DISCONNECTED, 1, &Parm);
1042 LogFlowFunc(("Cancelled host message %u (%s) with idContext=%#x -> %Rrc\n",
1043 pCurMsg->mType, GstCtrlHostMsgtoStr((eHostMsg)pCurMsg->mType), pCurMsg->m_idContext, rc2));
1044 RT_NOREF(rc2);
1045
1046 pCurMsg->Delete();
1047 }
1048
1049 /*
1050 * Delete the client state.
1051 */
1052 pThis->m_ClientStateMap.erase(idClient);
1053 if (pClient->m_idSession != UINT32_MAX)
1054 pThis->m_SessionIdMap.erase(pClient->m_idSession);
1055 pClient->~ClientState();
1056
1057 /*
1058 * If it's the master disconnecting, we need to reset related globals.
1059 */
1060 if (idClient == pThis->m_idMasterClient)
1061 {
1062 pThis->m_pMasterClient = NULL;
1063 pThis->m_idMasterClient = UINT32_MAX;
1064
1065 GstCtrlPreparedSession *pCur, *pNext;
1066 RTListForEachSafe(&pThis->m_PreparedSessions, pCur, pNext, GstCtrlPreparedSession, ListEntry)
1067 {
1068 RTListNodeRemove(&pCur->ListEntry);
1069 RTMemFree(pCur);
1070 }
1071 pThis->m_cPreparedSessions = 0;
1072 }
1073 else
1074 Assert(pClient != pThis->m_pMasterClient);
1075
1076 if (pThis->m_ClientStateMap.empty())
1077 pThis->m_fLegacyMode = true;
1078
1079 return VINF_SUCCESS;
1080}
1081
1082
1083/**
1084 * A client asks for the next message to process.
1085 *
1086 * This either fills in a pending host message into the client's parameter space
1087 * or defers the guest call until we have something from the host.
1088 *
1089 * @returns VBox status code.
1090 * @param pClient The client state.
1091 * @param hCall The client's call handle.
1092 * @param cParms Number of parameters.
1093 * @param paParms Array of parameters.
1094 */
1095int GstCtrlService::clientMsgOldGet(ClientState *pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1096{
1097 ASSERT_GUEST(pClient->m_idSession != UINT32_MAX || pClient->m_fIsMaster || pClient->m_fRestored);
1098
1099 /* Use the current (inbound) connection. */
1100 ClientRequest thisCon;
1101 thisCon.mHandle = hCall;
1102 thisCon.mNumParms = cParms;
1103 thisCon.mParms = paParms;
1104
1105 return pClient->OldRunCurrent(&thisCon);
1106}
1107
1108
1109/**
1110 * Implements GUEST_MAKE_ME_MASTER.
1111 *
1112 * @returns VBox status code.
1113 * @retval VINF_HGCM_ASYNC_EXECUTE on success (we complete the message here).
1114 * @retval VERR_ACCESS_DENIED if not using main VBoxGuest device not
1115 * @retval VERR_RESOURCE_BUSY if there is already a master.
1116 * @retval VERR_VERSION_MISMATCH if VBoxGuest didn't supply requestor info.
1117 * @retval VERR_WRONG_PARAMETER_COUNT
1118 *
1119 * @param pClient The client state.
1120 * @param hCall The client's call handle.
1121 * @param cParms Number of parameters.
1122 */
1123int GstCtrlService::clientMakeMeMaster(ClientState *pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms)
1124{
1125 /*
1126 * Validate the request.
1127 */
1128 ASSERT_GUEST_RETURN(cParms == 0, VERR_WRONG_PARAMETER_COUNT);
1129
1130 uint32_t fRequestor = mpHelpers->pfnGetRequestor(hCall);
1131 /* The next assertion triggers upgrading GAs on some linux guests. Problem is that VBoxService is
1132 restarted after installation but the kernel module hasn't been reloaded, so things are out
1133 of wack. Just reboot. */
1134 ASSERT_GUEST_LOGREL_MSG_RETURN(fRequestor != VMMDEV_REQUESTOR_LEGACY,
1135 ("Guest is using outdated VBoxGuest w/o requestor support.\n"
1136 "Please update guest additions (or restart guest if you just did)!\n"),
1137 VERR_VERSION_MISMATCH);
1138 ASSERT_GUEST_LOGREL_MSG_RETURN(!(fRequestor & VMMDEV_REQUESTOR_USER_DEVICE), ("fRequestor=%#x\n", fRequestor),
1139 VERR_ACCESS_DENIED);
1140
1141 /*
1142 * Do the work.
1143 */
1144 ASSERT_GUEST_MSG_RETURN(m_idMasterClient == pClient->m_idClient || m_idMasterClient == UINT32_MAX,
1145 ("Already have master session %RU32, refusing %RU32.\n", m_idMasterClient, pClient->m_idClient),
1146 VERR_RESOURCE_BUSY);
1147 int rc = mpHelpers->pfnCallComplete(hCall, VINF_SUCCESS);
1148 if (RT_SUCCESS(rc))
1149 {
1150 m_pMasterClient = pClient;
1151 m_idMasterClient = pClient->m_idClient;
1152 m_fLegacyMode = false;
1153 pClient->m_fIsMaster = true;
1154 Log(("[Client %RU32] is master.\n", pClient->m_idClient));
1155 }
1156 else
1157 LogFunc(("pfnCallComplete -> %Rrc\n", rc));
1158
1159 return VINF_HGCM_ASYNC_EXECUTE;
1160}
1161
1162
1163/**
1164 * Implements GUEST_MSG_REPORT_FEATURES.
1165 *
1166 * @returns VBox status code.
1167 * @retval VINF_HGCM_ASYNC_EXECUTE on success (we complete the message here).
1168 * @retval VERR_ACCESS_DENIED if not master
1169 * @retval VERR_INVALID_PARAMETER if bit 63 in the 2nd parameter isn't set.
1170 * @retval VERR_WRONG_PARAMETER_COUNT
1171 *
1172 * @param pClient The client state.
1173 * @param hCall The client's call handle.
1174 * @param cParms Number of parameters.
1175 * @param paParms Array of parameters.
1176 */
1177int GstCtrlService::clientReportFeatures(ClientState *pClient, VBOXHGCMCALLHANDLE hCall,
1178 uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1179{
1180 /*
1181 * Validate the request.
1182 */
1183 ASSERT_GUEST_RETURN(cParms == 2, VERR_WRONG_PARAMETER_COUNT);
1184 ASSERT_GUEST_RETURN(paParms[0].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE);
1185 uint64_t const fFeatures0 = paParms[0].u.uint64;
1186 ASSERT_GUEST_RETURN(paParms[1].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE);
1187 uint64_t const fFeatures1 = paParms[1].u.uint64;
1188 ASSERT_GUEST_RETURN(fFeatures1 & VBOX_GUESTCTRL_GF_1_MUST_BE_ONE, VERR_INVALID_PARAMETER);
1189
1190 ASSERT_GUEST_RETURN(pClient->m_fIsMaster, VERR_ACCESS_DENIED);
1191
1192 /*
1193 * Do the work.
1194 */
1195 VBOXHGCMSVCPARM aCopyForMain[2] = { paParms[0], paParms[1] };
1196
1197 paParms[0].u.uint64 = g_fGstCtrlHostFeatures0;
1198 paParms[1].u.uint64 = 0;
1199
1200 int rc = mpHelpers->pfnCallComplete(hCall, VINF_SUCCESS);
1201 if (RT_SUCCESS(rc))
1202 {
1203 m_fGuestFeatures0 = fFeatures0;
1204 m_fGuestFeatures1 = fFeatures1;
1205 Log(("[Client %RU32] reported features: %#RX64 %#RX64\n", pClient->m_idClient, fFeatures0, fFeatures1));
1206
1207 /*
1208 * Forward the info to main.
1209 */
1210 hostCallback(GUEST_MSG_REPORT_FEATURES, RT_ELEMENTS(aCopyForMain), aCopyForMain);
1211 }
1212 else
1213 LogFunc(("pfnCallComplete -> %Rrc\n", rc));
1214
1215 return VINF_HGCM_ASYNC_EXECUTE;
1216}
1217
1218
1219/**
1220 * Implements GUEST_MSG_QUERY_FEATURES.
1221 *
1222 * @returns VBox status code.
1223 * @retval VINF_HGCM_ASYNC_EXECUTE on success (we complete the message here).
1224 * @retval VERR_WRONG_PARAMETER_COUNT
1225 *
1226 * @param pClient The client state.
1227 * @param hCall The client's call handle.
1228 * @param cParms Number of parameters.
1229 * @param paParms Array of parameters.
1230 */
1231int GstCtrlService::clientQueryFeatures(ClientState *pClient,
1232 VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1233{
1234 RT_NOREF(pClient);
1235
1236 /*
1237 * Validate the request.
1238 */
1239 ASSERT_GUEST_RETURN(cParms == 2, VERR_WRONG_PARAMETER_COUNT);
1240 ASSERT_GUEST_RETURN(paParms[0].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE);
1241 ASSERT_GUEST_RETURN(paParms[1].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE);
1242 ASSERT_GUEST(paParms[1].u.uint64 & RT_BIT_64(63));
1243
1244 /*
1245 * Do the work.
1246 */
1247 paParms[0].u.uint64 = g_fGstCtrlHostFeatures0;
1248 paParms[1].u.uint64 = 0;
1249 int rc = mpHelpers->pfnCallComplete(hCall, VINF_SUCCESS);
1250 if (RT_SUCCESS(rc))
1251 {
1252 Log(("[Client %RU32] query features: %#RX64 0\n", pClient->m_idClient, g_fGstCtrlHostFeatures0));
1253 }
1254 else
1255 LogFunc(("pfnCallComplete -> %Rrc\n", rc));
1256
1257 return VINF_HGCM_ASYNC_EXECUTE;
1258}
1259
1260
1261/**
1262 * Implements GUEST_MSG_PEEK_WAIT and GUEST_MSG_PEEK_NOWAIT.
1263 *
1264 * @returns VBox status code.
1265 * @retval VINF_SUCCESS if a message was pending and is being returned.
1266 * @retval VERR_TRY_AGAIN if no message pending and not blocking.
1267 * @retval VERR_RESOURCE_BUSY if another read already made a waiting call.
1268 * @retval VINF_HGCM_ASYNC_EXECUTE if message wait is pending.
1269 *
1270 * @param pClient The client state.
1271 * @param hCall The client's call handle.
1272 * @param cParms Number of parameters.
1273 * @param paParms Array of parameters.
1274 * @param fWait Set if we should wait for a message, clear if to return
1275 * immediately.
1276 */
1277int GstCtrlService::clientMsgPeek(ClientState *pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool fWait)
1278{
1279 /*
1280 * Validate the request.
1281 */
1282 ASSERT_GUEST_MSG_RETURN(cParms >= 2, ("cParms=%u!\n", cParms), VERR_WRONG_PARAMETER_COUNT);
1283
1284 uint64_t idRestoreCheck = 0;
1285 uint32_t i = 0;
1286 if (paParms[i].type == VBOX_HGCM_SVC_PARM_64BIT)
1287 {
1288 idRestoreCheck = paParms[0].u.uint64;
1289 paParms[0].u.uint64 = 0;
1290 i++;
1291 }
1292 for (; i < cParms; i++)
1293 {
1294 ASSERT_GUEST_MSG_RETURN(paParms[i].type == VBOX_HGCM_SVC_PARM_32BIT, ("#%u type=%u\n", i, paParms[i].type),
1295 VERR_WRONG_PARAMETER_TYPE);
1296 paParms[i].u.uint32 = 0;
1297 }
1298
1299 /*
1300 * Check restore session ID.
1301 */
1302 if (idRestoreCheck != 0)
1303 {
1304 uint64_t idRestore = mpHelpers->pfnGetVMMDevSessionId(mpHelpers);
1305 if (idRestoreCheck != idRestore)
1306 {
1307 paParms[0].u.uint64 = idRestore;
1308 LogFlowFunc(("[Client %RU32] GUEST_MSG_PEEK_XXXX -> VERR_VM_RESTORED (%#RX64 -> %#RX64)\n",
1309 pClient->m_idClient, idRestoreCheck, idRestore));
1310 return VERR_VM_RESTORED;
1311 }
1312 Assert(!mpHelpers->pfnIsCallRestored(hCall));
1313 }
1314
1315 /*
1316 * Return information about the first message if one is pending in the list.
1317 */
1318 HostMsg *pFirstMsg = RTListGetFirstCpp(&pClient->m_HostMsgList, HostMsg, m_ListEntry);
1319 if (pFirstMsg)
1320 {
1321 pFirstMsg->setPeekReturn(paParms, cParms);
1322 LogFlowFunc(("[Client %RU32] GUEST_MSG_PEEK_XXXX -> VINF_SUCCESS (idMsg=%u (%s), cParms=%u)\n",
1323 pClient->m_idClient, pFirstMsg->mType, GstCtrlHostMsgtoStr((eHostMsg)pFirstMsg->mType), pFirstMsg->mParmCount));
1324 return VINF_SUCCESS;
1325 }
1326
1327 /*
1328 * If we cannot wait, fail the call.
1329 */
1330 if (!fWait)
1331 {
1332 LogFlowFunc(("[Client %RU32] GUEST_MSG_PEEK_NOWAIT -> VERR_TRY_AGAIN\n", pClient->m_idClient));
1333 return VERR_TRY_AGAIN;
1334 }
1335
1336 /*
1337 * Wait for the host to queue a message for this client.
1338 */
1339 ASSERT_GUEST_MSG_RETURN(pClient->m_enmPendingMsg == 0, ("Already pending! (idClient=%RU32)\n", pClient->m_idClient),
1340 VERR_RESOURCE_BUSY);
1341 pClient->m_PendingReq.mHandle = hCall;
1342 pClient->m_PendingReq.mNumParms = cParms;
1343 pClient->m_PendingReq.mParms = paParms;
1344 pClient->m_enmPendingMsg = GUEST_MSG_PEEK_WAIT;
1345 LogFlowFunc(("[Client %RU32] Is now in pending mode...\n", pClient->m_idClient));
1346 return VINF_HGCM_ASYNC_EXECUTE;
1347}
1348
1349/**
1350 * Implements GUEST_MSG_GET.
1351 *
1352 * @returns VBox status code.
1353 * @retval VINF_SUCCESS if message retrieved and removed from the pending queue.
1354 * @retval VERR_TRY_AGAIN if no message pending.
1355 * @retval VERR_BUFFER_OVERFLOW if a parmeter buffer is too small. The buffer
1356 * size was updated to reflect the required size, though this isn't yet
1357 * forwarded to the guest. (The guest is better of using peek with
1358 * parameter count + 2 parameters to get the sizes.)
1359 * @retval VERR_MISMATCH if the incoming message ID does not match the pending.
1360 * @retval VINF_HGCM_ASYNC_EXECUTE if message was completed already.
1361 *
1362 * @param pClient The client state.
1363 * @param hCall The client's call handle.
1364 * @param cParms Number of parameters.
1365 * @param paParms Array of parameters.
1366 */
1367int GstCtrlService::clientMsgGet(ClientState *pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1368{
1369 /*
1370 * Validate the request.
1371 *
1372 * The weird first parameter logic is due to GUEST_MSG_WAIT compatibility
1373 * (don't want to rewrite all the message structures).
1374 */
1375 uint32_t const idMsgExpected = cParms > 0 && paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT ? paParms[0].u.uint32
1376 : cParms > 0 && paParms[0].type == VBOX_HGCM_SVC_PARM_64BIT ? paParms[0].u.uint64
1377 : UINT32_MAX;
1378
1379 /*
1380 * Return information about the first message if one is pending in the list.
1381 */
1382 HostMsg *pFirstMsg = RTListGetFirstCpp(&pClient->m_HostMsgList, HostMsg, m_ListEntry);
1383 if (pFirstMsg)
1384 {
1385
1386 ASSERT_GUEST_MSG_RETURN(pFirstMsg->mType == idMsgExpected || idMsgExpected == UINT32_MAX,
1387 ("idMsg=%u (%s) cParms=%u, caller expected %u (%s) and %u\n",
1388 pFirstMsg->mType, GstCtrlHostMsgtoStr((eHostMsg)pFirstMsg->mType), pFirstMsg->mParmCount,
1389 idMsgExpected, GstCtrlHostMsgtoStr((eHostMsg)idMsgExpected), cParms),
1390 VERR_MISMATCH);
1391 ASSERT_GUEST_MSG_RETURN(pFirstMsg->mParmCount == cParms,
1392 ("idMsg=%u (%s) cParms=%u, caller expected %u (%s) and %u\n",
1393 pFirstMsg->mType, GstCtrlHostMsgtoStr((eHostMsg)pFirstMsg->mType), pFirstMsg->mParmCount,
1394 idMsgExpected, GstCtrlHostMsgtoStr((eHostMsg)idMsgExpected), cParms),
1395 VERR_WRONG_PARAMETER_COUNT);
1396
1397 /* Check the parameter types. */
1398 for (uint32_t i = 0; i < cParms; i++)
1399 ASSERT_GUEST_MSG_RETURN(pFirstMsg->mpParms[i].type == paParms[i].type,
1400 ("param #%u: type %u, caller expected %u (idMsg=%u %s)\n", i, pFirstMsg->mpParms[i].type,
1401 paParms[i].type, pFirstMsg->mType, GstCtrlHostMsgtoStr((eHostMsg)pFirstMsg->mType)),
1402 VERR_WRONG_PARAMETER_TYPE);
1403
1404 /*
1405 * Copy out the parameters.
1406 *
1407 * No assertions on buffer overflows, and keep going till the end so we can
1408 * communicate all the required buffer sizes.
1409 */
1410 int rc = VINF_SUCCESS;
1411 for (uint32_t i = 0; i < cParms; i++)
1412 switch (pFirstMsg->mpParms[i].type)
1413 {
1414 case VBOX_HGCM_SVC_PARM_32BIT:
1415 paParms[i].u.uint32 = pFirstMsg->mpParms[i].u.uint32;
1416 break;
1417
1418 case VBOX_HGCM_SVC_PARM_64BIT:
1419 paParms[i].u.uint64 = pFirstMsg->mpParms[i].u.uint64;
1420 break;
1421
1422 case VBOX_HGCM_SVC_PARM_PTR:
1423 {
1424 uint32_t const cbSrc = pFirstMsg->mpParms[i].u.pointer.size;
1425 uint32_t const cbDst = paParms[i].u.pointer.size;
1426 paParms[i].u.pointer.size = cbSrc; /** @todo Check if this is safe in other layers...
1427 * Update: Safe, yes, but VMMDevHGCM doesn't pass it along. */
1428 if (cbSrc <= cbDst)
1429 memcpy(paParms[i].u.pointer.addr, pFirstMsg->mpParms[i].u.pointer.addr, cbSrc);
1430 else
1431 rc = VERR_BUFFER_OVERFLOW;
1432 break;
1433 }
1434
1435 default:
1436 AssertMsgFailed(("#%u: %u\n", i, pFirstMsg->mpParms[i].type));
1437 rc = VERR_INTERNAL_ERROR;
1438 break;
1439 }
1440 if (RT_SUCCESS(rc))
1441 {
1442 /*
1443 * Complete the message and remove the pending message unless the
1444 * guest raced us and cancelled this call in the meantime.
1445 */
1446 AssertPtr(mpHelpers);
1447 rc = mpHelpers->pfnCallComplete(hCall, rc);
1448 if (rc != VERR_CANCELLED)
1449 {
1450 RTListNodeRemove(&pFirstMsg->m_ListEntry);
1451 pFirstMsg->Delete();
1452 }
1453 else
1454 LogFunc(("pfnCallComplete -> %Rrc\n", rc));
1455 return VINF_HGCM_ASYNC_EXECUTE; /* The caller must not complete it. */
1456 }
1457 return rc;
1458 }
1459
1460 paParms[0].u.uint32 = 0;
1461 paParms[1].u.uint32 = 0;
1462 LogFlowFunc(("[Client %RU32] GUEST_MSG_GET -> VERR_TRY_AGAIN\n", pClient->m_idClient));
1463 return VERR_TRY_AGAIN;
1464}
1465
1466/**
1467 * Implements GUEST_MSG_CANCEL.
1468 *
1469 * @returns VBox status code.
1470 * @retval VINF_SUCCESS if cancelled any calls.
1471 * @retval VWRN_NOT_FOUND if no callers.
1472 * @retval VINF_HGCM_ASYNC_EXECUTE if message wait is pending.
1473 *
1474 * @param pClient The client state.
1475 * @param cParms Number of parameters.
1476 */
1477int GstCtrlService::clientMsgCancel(ClientState *pClient, uint32_t cParms)
1478{
1479 /*
1480 * Validate the request.
1481 */
1482 ASSERT_GUEST_MSG_RETURN(cParms == 0, ("cParms=%u!\n", cParms), VERR_WRONG_PARAMETER_COUNT);
1483
1484 /*
1485 * Execute.
1486 */
1487 if (pClient->m_enmPendingMsg != 0)
1488 {
1489 pClient->CancelWaiting();
1490 return VINF_SUCCESS;
1491 }
1492 return VWRN_NOT_FOUND;
1493}
1494
1495
1496/**
1497 * Implements GUEST_MSG_SKIP.
1498 *
1499 * @returns VBox status code.
1500 * @retval VINF_HGCM_ASYNC_EXECUTE on success as we complete the message.
1501 * @retval VERR_NOT_FOUND if no message pending.
1502 *
1503 * @param pClient The client state.
1504 * @param hCall The call handle for completing it.
1505 * @param cParms Number of parameters.
1506 * @param paParms The parameters.
1507 */
1508int GstCtrlService::clientMsgSkip(ClientState *pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1509{
1510 /*
1511 * Validate the call.
1512 */
1513 ASSERT_GUEST_RETURN(cParms <= 2, VERR_WRONG_PARAMETER_COUNT);
1514
1515 int32_t rcSkip = VERR_NOT_SUPPORTED;
1516 if (cParms >= 1)
1517 {
1518 ASSERT_GUEST_RETURN(paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE);
1519 rcSkip = (int32_t)paParms[0].u.uint32;
1520 }
1521
1522 uint32_t idMsg = UINT32_MAX;
1523 if (cParms >= 2)
1524 {
1525 ASSERT_GUEST_RETURN(paParms[1].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE);
1526 idMsg = paParms[1].u.uint32;
1527 }
1528
1529 /*
1530 * Do the job.
1531 */
1532 HostMsg *pFirstMsg = RTListGetFirstCpp(&pClient->m_HostMsgList, HostMsg, m_ListEntry);
1533 if (pFirstMsg)
1534 {
1535 if ( pFirstMsg->mType == idMsg
1536 || idMsg == UINT32_MAX)
1537 {
1538 int rc = mpHelpers->pfnCallComplete(hCall, VINF_SUCCESS);
1539 if (RT_SUCCESS(rc))
1540 {
1541 /*
1542 * Remove the message from the queue.
1543 */
1544 Assert(RTListNodeIsFirst(&pClient->m_HostMsgList, &pFirstMsg->m_ListEntry) );
1545 RTListNodeRemove(&pFirstMsg->m_ListEntry);
1546
1547 /*
1548 * Compose a reply to the host service.
1549 */
1550 VBOXHGCMSVCPARM aReplyParams[5];
1551 HGCMSvcSetU32(&aReplyParams[0], pFirstMsg->m_idContext);
1552 switch (pFirstMsg->mType)
1553 {
1554 case HOST_MSG_EXEC_CMD:
1555 HGCMSvcSetU32(&aReplyParams[1], 0); /* pid */
1556 HGCMSvcSetU32(&aReplyParams[2], PROC_STS_ERROR); /* status */
1557 HGCMSvcSetU32(&aReplyParams[3], rcSkip); /* flags / whatever */
1558 HGCMSvcSetPv(&aReplyParams[4], NULL, 0); /* data buffer */
1559 hostCallback(GUEST_MSG_EXEC_STATUS, 5, aReplyParams);
1560 break;
1561
1562 case HOST_MSG_SESSION_CREATE:
1563 HGCMSvcSetU32(&aReplyParams[1], GUEST_SESSION_NOTIFYTYPE_ERROR); /* type */
1564 HGCMSvcSetU32(&aReplyParams[2], rcSkip); /* result */
1565 hostCallback(GUEST_MSG_SESSION_NOTIFY, 3, aReplyParams);
1566 break;
1567
1568 case HOST_MSG_EXEC_SET_INPUT:
1569 HGCMSvcSetU32(&aReplyParams[1], pFirstMsg->mParmCount >= 2 ? pFirstMsg->mpParms[1].u.uint32 : 0);
1570 HGCMSvcSetU32(&aReplyParams[2], INPUT_STS_ERROR); /* status */
1571 HGCMSvcSetU32(&aReplyParams[3], rcSkip); /* flags / whatever */
1572 HGCMSvcSetU32(&aReplyParams[4], 0); /* bytes consumed */
1573 hostCallback(GUEST_MSG_EXEC_INPUT_STATUS, 5, aReplyParams);
1574 break;
1575
1576 case HOST_MSG_FILE_OPEN:
1577 HGCMSvcSetU32(&aReplyParams[1], GUEST_FILE_NOTIFYTYPE_OPEN); /* type*/
1578 HGCMSvcSetU32(&aReplyParams[2], rcSkip); /* rc */
1579 HGCMSvcSetU32(&aReplyParams[3], VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pFirstMsg->m_idContext)); /* handle */
1580 hostCallback(GUEST_MSG_FILE_NOTIFY, 4, aReplyParams);
1581 break;
1582 case HOST_MSG_FILE_CLOSE:
1583 HGCMSvcSetU32(&aReplyParams[1], GUEST_FILE_NOTIFYTYPE_ERROR); /* type*/
1584 HGCMSvcSetU32(&aReplyParams[2], rcSkip); /* rc */
1585 hostCallback(GUEST_MSG_FILE_NOTIFY, 3, aReplyParams);
1586 break;
1587 case HOST_MSG_FILE_READ:
1588 case HOST_MSG_FILE_READ_AT:
1589 HGCMSvcSetU32(&aReplyParams[1], GUEST_FILE_NOTIFYTYPE_READ); /* type */
1590 HGCMSvcSetU32(&aReplyParams[2], rcSkip); /* rc */
1591 HGCMSvcSetPv(&aReplyParams[3], NULL, 0); /* data buffer */
1592 hostCallback(GUEST_MSG_FILE_NOTIFY, 4, aReplyParams);
1593 break;
1594 case HOST_MSG_FILE_WRITE:
1595 case HOST_MSG_FILE_WRITE_AT:
1596 HGCMSvcSetU32(&aReplyParams[1], GUEST_FILE_NOTIFYTYPE_WRITE); /* type */
1597 HGCMSvcSetU32(&aReplyParams[2], rcSkip); /* rc */
1598 HGCMSvcSetU32(&aReplyParams[3], 0); /* bytes written */
1599 hostCallback(GUEST_MSG_FILE_NOTIFY, 4, aReplyParams);
1600 break;
1601 case HOST_MSG_FILE_SEEK:
1602 HGCMSvcSetU32(&aReplyParams[1], GUEST_FILE_NOTIFYTYPE_SEEK); /* type */
1603 HGCMSvcSetU32(&aReplyParams[2], rcSkip); /* rc */
1604 HGCMSvcSetU64(&aReplyParams[3], 0); /* actual */
1605 hostCallback(GUEST_MSG_FILE_NOTIFY, 4, aReplyParams);
1606 break;
1607 case HOST_MSG_FILE_TELL:
1608 HGCMSvcSetU32(&aReplyParams[1], GUEST_FILE_NOTIFYTYPE_TELL); /* type */
1609 HGCMSvcSetU32(&aReplyParams[2], rcSkip); /* rc */
1610 HGCMSvcSetU64(&aReplyParams[3], 0); /* actual */
1611 hostCallback(GUEST_MSG_FILE_NOTIFY, 4, aReplyParams);
1612 break;
1613 case HOST_MSG_FILE_SET_SIZE:
1614 HGCMSvcSetU32(&aReplyParams[1], GUEST_FILE_NOTIFYTYPE_SET_SIZE); /* type */
1615 HGCMSvcSetU32(&aReplyParams[2], rcSkip); /* rc */
1616 HGCMSvcSetU64(&aReplyParams[3], 0); /* actual */
1617 hostCallback(GUEST_MSG_FILE_NOTIFY, 4, aReplyParams);
1618 break;
1619
1620 case HOST_MSG_EXEC_GET_OUTPUT: /** @todo This can't be right/work. */
1621 case HOST_MSG_EXEC_TERMINATE: /** @todo This can't be right/work. */
1622 case HOST_MSG_EXEC_WAIT_FOR: /** @todo This can't be right/work. */
1623 case HOST_MSG_PATH_USER_DOCUMENTS:
1624 case HOST_MSG_PATH_USER_HOME:
1625 case HOST_MSG_PATH_RENAME:
1626 case HOST_MSG_DIR_REMOVE:
1627 default:
1628 HGCMSvcSetU32(&aReplyParams[1], pFirstMsg->mType);
1629 HGCMSvcSetU32(&aReplyParams[2], (uint32_t)rcSkip);
1630 HGCMSvcSetPv(&aReplyParams[3], NULL, 0);
1631 hostCallback(GUEST_MSG_REPLY, 4, aReplyParams);
1632 break;
1633 }
1634
1635 /*
1636 * Free the message.
1637 */
1638 pFirstMsg->Delete();
1639 }
1640 else
1641 LogFunc(("pfnCallComplete -> %Rrc\n", rc));
1642 return VINF_HGCM_ASYNC_EXECUTE; /* The caller must not complete it. */
1643 }
1644 LogFunc(("Warning: GUEST_MSG_SKIP mismatch! Found %u, caller expected %u!\n", pFirstMsg->mType, idMsg));
1645 return VERR_MISMATCH;
1646 }
1647 return VERR_NOT_FOUND;
1648}
1649
1650
1651/**
1652 * Implements GUEST_SESSION_PREPARE.
1653 *
1654 * @returns VBox status code.
1655 * @retval VINF_HGCM_ASYNC_EXECUTE on success as we complete the message.
1656 * @retval VERR_OUT_OF_RESOURCES if too many pending sessions hanging around.
1657 * @retval VERR_OUT_OF_RANGE if the session ID outside the allowed range.
1658 * @retval VERR_BUFFER_OVERFLOW if key too large.
1659 * @retval VERR_BUFFER_UNDERFLOW if key too small.
1660 * @retval VERR_ACCESS_DENIED if not master or in legacy mode.
1661 * @retval VERR_DUPLICATE if the session ID has been prepared already.
1662 *
1663 * @param pClient The client state.
1664 * @param hCall The call handle for completing it.
1665 * @param cParms Number of parameters.
1666 * @param paParms The parameters.
1667 */
1668int GstCtrlService::clientSessionPrepare(ClientState *pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1669{
1670 /*
1671 * Validate parameters.
1672 */
1673 ASSERT_GUEST_RETURN(cParms == 2, VERR_WRONG_PARAMETER_COUNT);
1674 ASSERT_GUEST_RETURN(paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE);
1675 uint32_t const idSession = paParms[0].u.uint32;
1676 ASSERT_GUEST_RETURN(idSession >= 1, VERR_OUT_OF_RANGE);
1677 ASSERT_GUEST_RETURN(idSession <= 0xfff0, VERR_OUT_OF_RANGE);
1678
1679 ASSERT_GUEST_RETURN(paParms[1].type == VBOX_HGCM_SVC_PARM_PTR, VERR_WRONG_PARAMETER_TYPE);
1680 uint32_t const cbKey = paParms[1].u.pointer.size;
1681 void const *pvKey = paParms[1].u.pointer.addr;
1682 ASSERT_GUEST_RETURN(cbKey >= 64, VERR_BUFFER_UNDERFLOW);
1683 ASSERT_GUEST_RETURN(cbKey <= _16K, VERR_BUFFER_OVERFLOW);
1684
1685 ASSERT_GUEST_RETURN(pClient->m_fIsMaster, VERR_ACCESS_DENIED);
1686 ASSERT_GUEST_RETURN(!m_fLegacyMode, VERR_ACCESS_DENIED);
1687 Assert(m_idMasterClient == pClient->m_idClient);
1688 Assert(m_pMasterClient == pClient);
1689
1690 /* Now that we know it's the master, we can check for session ID duplicates. */
1691 GstCtrlPreparedSession *pCur;
1692 RTListForEach(&m_PreparedSessions, pCur, GstCtrlPreparedSession, ListEntry)
1693 {
1694 ASSERT_GUEST_RETURN(pCur->idSession != idSession, VERR_DUPLICATE);
1695 }
1696
1697 /*
1698 * Make a copy of the session ID and key.
1699 */
1700 ASSERT_GUEST_RETURN(m_cPreparedSessions < 128, VERR_OUT_OF_RESOURCES);
1701
1702 GstCtrlPreparedSession *pPrepped = (GstCtrlPreparedSession *)RTMemAlloc(RT_UOFFSETOF_DYN(GstCtrlPreparedSession, abKey[cbKey]));
1703 AssertReturn(pPrepped, VERR_NO_MEMORY);
1704 pPrepped->idSession = idSession;
1705 pPrepped->cbKey = cbKey;
1706 memcpy(pPrepped->abKey, pvKey, cbKey);
1707
1708 RTListAppend(&m_PreparedSessions, &pPrepped->ListEntry);
1709 m_cPreparedSessions++;
1710
1711 /*
1712 * Try complete the message.
1713 */
1714 int rc = mpHelpers->pfnCallComplete(hCall, VINF_SUCCESS);
1715 if (RT_SUCCESS(rc))
1716 LogFlow(("Prepared %u with a %#x byte key (%u pending).\n", idSession, cbKey, m_cPreparedSessions));
1717 else
1718 {
1719 LogFunc(("pfnCallComplete -> %Rrc\n", rc));
1720 RTListNodeRemove(&pPrepped->ListEntry);
1721 RTMemFree(pPrepped);
1722 m_cPreparedSessions--;
1723 }
1724 return VINF_HGCM_ASYNC_EXECUTE; /* The caller must not complete it. */
1725}
1726
1727
1728/**
1729 * Implements GUEST_SESSION_CANCEL_PREPARED.
1730 *
1731 * @returns VBox status code.
1732 * @retval VINF_HGCM_ASYNC_EXECUTE on success as we complete the message.
1733 * @retval VWRN_NOT_FOUND if no session with the specified ID.
1734 * @retval VERR_ACCESS_DENIED if not master or in legacy mode.
1735 *
1736 * @param pClient The client state.
1737 * @param cParms Number of parameters.
1738 * @param paParms The parameters.
1739 */
1740int GstCtrlService::clientSessionCancelPrepared(ClientState *pClient, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1741{
1742 /*
1743 * Validate parameters.
1744 */
1745 ASSERT_GUEST_RETURN(cParms == 1, VERR_WRONG_PARAMETER_COUNT);
1746 ASSERT_GUEST_RETURN(paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE);
1747 uint32_t const idSession = paParms[0].u.uint32;
1748
1749 ASSERT_GUEST_RETURN(pClient->m_fIsMaster, VERR_ACCESS_DENIED);
1750 ASSERT_GUEST_RETURN(!m_fLegacyMode, VERR_ACCESS_DENIED);
1751 Assert(m_idMasterClient == pClient->m_idClient);
1752 Assert(m_pMasterClient == pClient);
1753
1754 /*
1755 * Do the work.
1756 */
1757 int rc = VWRN_NOT_FOUND;
1758 if (idSession == UINT32_MAX)
1759 {
1760 GstCtrlPreparedSession *pCur, *pNext;
1761 RTListForEachSafe(&m_PreparedSessions, pCur, pNext, GstCtrlPreparedSession, ListEntry)
1762 {
1763 RTListNodeRemove(&pCur->ListEntry);
1764 RTMemFree(pCur);
1765 rc = VINF_SUCCESS;
1766 }
1767 m_cPreparedSessions = 0;
1768 }
1769 else
1770 {
1771 GstCtrlPreparedSession *pCur, *pNext;
1772 RTListForEachSafe(&m_PreparedSessions, pCur, pNext, GstCtrlPreparedSession, ListEntry)
1773 {
1774 if (pCur->idSession == idSession)
1775 {
1776 RTListNodeRemove(&pCur->ListEntry);
1777 RTMemFree(pCur);
1778 m_cPreparedSessions -= 1;
1779 rc = VINF_SUCCESS;
1780 break;
1781 }
1782 }
1783 }
1784 return VINF_SUCCESS;
1785}
1786
1787
1788/**
1789 * Implements GUEST_SESSION_ACCEPT.
1790 *
1791 * @returns VBox status code.
1792 * @retval VINF_HGCM_ASYNC_EXECUTE on success as we complete the message.
1793 * @retval VERR_NOT_FOUND if the specified session ID wasn't found.
1794 * @retval VERR_MISMATCH if the key didn't match.
1795 * @retval VERR_ACCESS_DENIED if we're in legacy mode or is master.
1796 * @retval VERR_RESOURCE_BUSY if the client is already associated with a
1797 * session.
1798 *
1799 * @param pClient The client state.
1800 * @param hCall The call handle for completing it.
1801 * @param cParms Number of parameters.
1802 * @param paParms The parameters.
1803 */
1804int GstCtrlService::clientSessionAccept(ClientState *pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1805{
1806 /*
1807 * Validate parameters.
1808 */
1809 ASSERT_GUEST_RETURN(cParms == 2, VERR_WRONG_PARAMETER_COUNT);
1810 ASSERT_GUEST_RETURN(paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE);
1811 uint32_t const idSession = paParms[0].u.uint32;
1812 ASSERT_GUEST_RETURN(idSession >= 1, VERR_OUT_OF_RANGE);
1813 ASSERT_GUEST_RETURN(idSession <= 0xfff0, VERR_OUT_OF_RANGE);
1814
1815 ASSERT_GUEST_RETURN(paParms[1].type == VBOX_HGCM_SVC_PARM_PTR, VERR_WRONG_PARAMETER_TYPE);
1816 uint32_t const cbKey = paParms[1].u.pointer.size;
1817 void const *pvKey = paParms[1].u.pointer.addr;
1818 ASSERT_GUEST_RETURN(cbKey >= 64, VERR_BUFFER_UNDERFLOW);
1819 ASSERT_GUEST_RETURN(cbKey <= _16K, VERR_BUFFER_OVERFLOW);
1820
1821 ASSERT_GUEST_RETURN(!pClient->m_fIsMaster, VERR_ACCESS_DENIED);
1822 ASSERT_GUEST_RETURN(!m_fLegacyMode, VERR_ACCESS_DENIED);
1823 Assert(m_idMasterClient != pClient->m_idClient);
1824 Assert(m_pMasterClient != pClient);
1825 ASSERT_GUEST_RETURN(pClient->m_idSession == UINT32_MAX, VERR_RESOURCE_BUSY);
1826
1827 /*
1828 * Look for the specified session and match the key to it.
1829 */
1830 GstCtrlPreparedSession *pCur;
1831 RTListForEach(&m_PreparedSessions, pCur, GstCtrlPreparedSession, ListEntry)
1832 {
1833 if (pCur->idSession == idSession)
1834 {
1835 if ( pCur->cbKey == cbKey
1836 && memcmp(pCur->abKey, pvKey, cbKey) == 0)
1837 {
1838 /*
1839 * We've got a match.
1840 * Try insert it into the sessio ID map and complete the request.
1841 */
1842 try
1843 {
1844 m_SessionIdMap[idSession] = pClient;
1845 }
1846 catch (std::bad_alloc &)
1847 {
1848 LogFunc(("Out of memory!\n"));
1849 return VERR_NO_MEMORY;
1850 }
1851
1852 int rc = mpHelpers->pfnCallComplete(hCall, VINF_SUCCESS);
1853 if (RT_SUCCESS(rc))
1854 {
1855 pClient->m_idSession = idSession;
1856
1857 RTListNodeRemove(&pCur->ListEntry);
1858 RTMemFree(pCur);
1859 m_cPreparedSessions -= 1;
1860 Log(("[Client %RU32] accepted session id %u.\n", pClient->m_idClient, idSession));
1861 }
1862 else
1863 {
1864 LogFunc(("pfnCallComplete -> %Rrc\n", rc));
1865 m_SessionIdMap.erase(idSession);
1866 }
1867 return VINF_HGCM_ASYNC_EXECUTE; /* The caller must not complete it. */
1868 }
1869 LogFunc(("Key mismatch for %u!\n", pClient->m_idClient));
1870 return VERR_MISMATCH;
1871 }
1872 }
1873
1874 LogFunc(("No client prepared for %u!\n", pClient->m_idClient));
1875 return VERR_NOT_FOUND;
1876}
1877
1878
1879/**
1880 * Client asks another client (guest) session to close.
1881 *
1882 * @returns VBox status code.
1883 * @param pClient The client state.
1884 * @param cParms Number of parameters.
1885 * @param paParms Array of parameters.
1886 */
1887int GstCtrlService::clientSessionCloseOther(ClientState *pClient, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1888{
1889 /*
1890 * Validate input.
1891 */
1892 ASSERT_GUEST_RETURN(cParms == 2, VERR_WRONG_PARAMETER_COUNT);
1893 ASSERT_GUEST_RETURN(paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE);
1894 uint32_t const idContext = paParms[0].u.uint32;
1895
1896 ASSERT_GUEST_RETURN(paParms[1].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE);
1897 uint32_t const fFlags = paParms[1].u.uint32;
1898
1899 ASSERT_GUEST_RETURN(pClient->m_fIsMaster || (m_fLegacyMode && pClient->m_idSession == UINT32_MAX), VERR_ACCESS_DENIED);
1900
1901 /*
1902 * Forward the message to the destiation.
1903 * Since we modify the first parameter, we must make a copy of the parameters.
1904 */
1905 VBOXHGCMSVCPARM aParms[2];
1906 HGCMSvcSetU64(&aParms[0], idContext | VBOX_GUESTCTRL_DST_SESSION);
1907 HGCMSvcSetU32(&aParms[1], fFlags);
1908 int rc = hostProcessMessage(HOST_MSG_SESSION_CLOSE, RT_ELEMENTS(aParms), aParms);
1909
1910 LogFlowFunc(("Closing guest context ID=%RU32 (from client ID=%RU32) returned with rc=%Rrc\n", idContext, pClient->m_idClient, rc));
1911 return rc;
1912}
1913
1914
1915/**
1916 * For compatiblity with old additions only - filtering / set session ID.
1917 *
1918 * @return VBox status code.
1919 * @param pClient The client state.
1920 * @param cParms Number of parameters.
1921 * @param paParms Array of parameters.
1922 */
1923int GstCtrlService::clientMsgOldFilterSet(ClientState *pClient, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1924{
1925 /*
1926 * Validate input and access.
1927 */
1928 ASSERT_GUEST_RETURN(cParms == 4, VERR_WRONG_PARAMETER_COUNT);
1929 ASSERT_GUEST_RETURN(paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE);
1930 uint32_t uValue = paParms[0].u.uint32;
1931 ASSERT_GUEST_RETURN(paParms[1].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE);
1932 uint32_t fMaskAdd = paParms[1].u.uint32;
1933 ASSERT_GUEST_RETURN(paParms[2].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE);
1934 uint32_t fMaskRemove = paParms[2].u.uint32;
1935 ASSERT_GUEST_RETURN(paParms[3].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE); /* flags, unused */
1936
1937 /*
1938 * We have a bunch of expectations here:
1939 * - Never called in non-legacy mode.
1940 * - Only called once per session.
1941 * - Never called by the master session.
1942 * - Clients that doesn't wish for any messages passes all zeros.
1943 * - All other calls has a unique session ID.
1944 */
1945 ASSERT_GUEST_LOGREL_RETURN(m_fLegacyMode, VERR_WRONG_ORDER);
1946 ASSERT_GUEST_LOGREL_MSG_RETURN(pClient->m_idSession == UINT32_MAX, ("m_idSession=%#x\n", pClient->m_idSession),
1947 VERR_WRONG_ORDER);
1948 ASSERT_GUEST_LOGREL_RETURN(!pClient->m_fIsMaster, VERR_WRONG_ORDER);
1949
1950 if (uValue == 0)
1951 {
1952 ASSERT_GUEST_LOGREL(fMaskAdd == 0);
1953 ASSERT_GUEST_LOGREL(fMaskRemove == 0);
1954 /* Nothing to do, already muted (UINT32_MAX). */
1955 }
1956 else
1957 {
1958 ASSERT_GUEST_LOGREL(fMaskAdd == UINT32_C(0xf8000000));
1959 ASSERT_GUEST_LOGREL(fMaskRemove == 0);
1960
1961 uint32_t idSession = VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(uValue);
1962 ASSERT_GUEST_LOGREL_MSG_RETURN(idSession > 0, ("idSession=%u (%#x)\n", idSession, uValue), VERR_OUT_OF_RANGE);
1963
1964 ClientStateMap::iterator ItConflict = m_SessionIdMap.find(idSession);
1965 ASSERT_GUEST_LOGREL_MSG_RETURN(ItConflict == m_SessionIdMap.end(),
1966 ("idSession=%u uValue=%#x idClient=%u; conflicting with client %u\n",
1967 idSession, uValue, pClient->m_idClient, ItConflict->second->m_idClient),
1968 VERR_DUPLICATE);
1969
1970 /* Commit it. */
1971 try
1972 {
1973 m_SessionIdMap[idSession] = pClient;
1974 }
1975 catch (std::bad_alloc &)
1976 {
1977 LogFunc(("Out of memory\n"));
1978 return VERR_NO_MEMORY;
1979 }
1980 pClient->m_idSession = idSession;
1981 }
1982 return VINF_SUCCESS;
1983}
1984
1985
1986/**
1987 * For compatibility with old additions only - skip the current message w/o
1988 * calling main code.
1989 *
1990 * Please note that we don't care if the caller cancelled the request, because
1991 * old additions code didn't give damn about VERR_INTERRUPT.
1992 *
1993 * @return VBox status code.
1994 * @param pClient The client state.
1995 * @param hCall The call handle for completing it.
1996 * @param cParms Number of parameters.
1997 */
1998int GstCtrlService::clientMsgOldSkip(ClientState *pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms)
1999{
2000 /*
2001 * Validate input and access.
2002 */
2003 ASSERT_GUEST_RETURN(cParms == 1, VERR_WRONG_PARAMETER_COUNT);
2004
2005 /*
2006 * Execute the request.
2007 *
2008 * Note! As it turns out the old and new skip should be mostly the same. The
2009 * pre-6.0 GAs (up to BETA3) has a hack which tries to issue a
2010 * VERR_NOT_SUPPORTED reply to unknown host requests, however the 5.2.x
2011 * and earlier GAs doesn't. We need old skip behavior only for the 6.0
2012 * beta GAs, nothing else.
2013 * So, we have to track whether they issued a MSG_REPLY or not. Wonderful.
2014 */
2015 HostMsg *pFirstMsg = RTListGetFirstCpp(&pClient->m_HostMsgList, HostMsg, m_ListEntry);
2016 if (pFirstMsg)
2017 {
2018 uint32_t const idMsg = pFirstMsg->mType;
2019 bool const f60BetaHackInPlay = pFirstMsg->m_f60BetaHackInPlay;
2020 int rc;
2021 if (!f60BetaHackInPlay)
2022 rc = clientMsgSkip(pClient, hCall, 0, NULL);
2023 else
2024 {
2025 RTListNodeRemove(&pFirstMsg->m_ListEntry);
2026 pFirstMsg->Delete();
2027 rc = VINF_SUCCESS;
2028 }
2029
2030 /* Reset legacy message wait/get state: */
2031 if (RT_SUCCESS(rc))
2032 {
2033 pClient->mHostMsgRc = VINF_SUCCESS;
2034 pClient->mHostMsgTries = 0;
2035 pClient->mPeekCount = 0;
2036 }
2037
2038 LogFlowFunc(("[Client %RU32] Legacy message skipping: Skipped %u (%s)%s!\n",
2039 pClient->m_idClient, idMsg, GstCtrlHostMsgtoStr((eHostMsg)idMsg), f60BetaHackInPlay ? " hack style" : ""));
2040 NOREF(idMsg);
2041 return rc;
2042 }
2043 LogFlowFunc(("[Client %RU32] Legacy message skipping: No messages pending!\n", pClient->m_idClient));
2044 return VINF_SUCCESS;
2045}
2046
2047
2048/**
2049 * Forwards client call to the Main API.
2050 *
2051 * This is typically notifications and replys.
2052 *
2053 * @returns VBox status code.
2054 * @param pClient The client state.
2055 * @param idMsg Message ID that occured.
2056 * @param cParms Number of parameters.
2057 * @param paParms Array of parameters.
2058 */
2059int GstCtrlService::clientToMain(ClientState *pClient, uint32_t idMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
2060{
2061 /*
2062 * Do input validation. This class of messages all have a 32-bit context ID as
2063 * the first parameter, so make sure it is there and appropriate for the caller.
2064 */
2065 ASSERT_GUEST_RETURN(cParms >= 1, VERR_WRONG_PARAMETER_COUNT);
2066 ASSERT_GUEST_RETURN(paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_COUNT);
2067 uint32_t const idContext = paParms[0].u.uint32;
2068 uint32_t const idSession = VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(idContext);
2069
2070 ASSERT_GUEST_MSG_RETURN( pClient->m_idSession == idSession
2071 || pClient->m_fIsMaster
2072 || ( m_fLegacyMode /* (see bugref:9313#c16) */
2073 && pClient->m_idSession == UINT32_MAX
2074 && ( idMsg == GUEST_MSG_EXEC_STATUS
2075 || idMsg == GUEST_MSG_SESSION_NOTIFY)),
2076 ("idSession=%u (CID=%#x) m_idSession=%u idClient=%u idMsg=%u (%s)\n", idSession, idContext,
2077 pClient->m_idSession, pClient->m_idClient, idMsg, GstCtrlGuestMsgToStr((eGuestMsg)idMsg)),
2078 VERR_ACCESS_DENIED);
2079
2080 /*
2081 * It seems okay, so make the call.
2082 */
2083 return hostCallback(idMsg, cParms, paParms);
2084}
2085
2086
2087/**
2088 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnCall}
2089 *
2090 * @note All functions which do not involve an unreasonable delay will be
2091 * handled synchronously. If needed, we will add a request handler
2092 * thread in future for those which do.
2093 * @thread HGCM
2094 */
2095/*static*/ DECLCALLBACK(void)
2096GstCtrlService::svcCall(void *pvService, VBOXHGCMCALLHANDLE hCall, uint32_t idClient, void *pvClient,
2097 uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[], uint64_t tsArrival)
2098{
2099 LogFlowFunc(("[Client %RU32] u32Function=%RU32 (%s), cParms=%RU32, paParms=0x%p\n",
2100 idClient, u32Function, GstCtrlGuestMsgToStr((eGuestMsg)u32Function), cParms, paParms));
2101 RT_NOREF(tsArrival, idClient);
2102
2103 /*
2104 * Convert opaque pointers to typed ones.
2105 */
2106 SELF *pThis = reinterpret_cast<SELF *>(pvService);
2107 AssertReturnVoidStmt(pThis, pThis->mpHelpers->pfnCallComplete(hCall, VERR_INTERNAL_ERROR_5));
2108 ClientState *pClient = reinterpret_cast<ClientState *>(pvClient);
2109 AssertReturnVoidStmt(pClient, pThis->mpHelpers->pfnCallComplete(hCall, VERR_INVALID_CLIENT_ID));
2110 Assert(pClient->m_idClient == idClient);
2111
2112 /*
2113 * Do the dispatching.
2114 */
2115 int rc;
2116 switch (u32Function)
2117 {
2118 case GUEST_MSG_MAKE_ME_MASTER:
2119 LogFlowFunc(("[Client %RU32] GUEST_MAKE_ME_MASTER\n", idClient));
2120 rc = pThis->clientMakeMeMaster(pClient, hCall, cParms);
2121 break;
2122 case GUEST_MSG_REPORT_FEATURES:
2123 LogFlowFunc(("[Client %RU32] GUEST_MSG_REPORT_FEATURES\n", idClient));
2124 rc = pThis->clientReportFeatures(pClient, hCall, cParms, paParms);
2125 break;
2126 case GUEST_MSG_QUERY_FEATURES:
2127 LogFlowFunc(("[Client %RU32] GUEST_MSG_QUERY_FEATURES\n", idClient));
2128 rc = pThis->clientQueryFeatures(pClient, hCall, cParms, paParms);
2129 break;
2130 case GUEST_MSG_PEEK_NOWAIT:
2131 LogFlowFunc(("[Client %RU32] GUEST_MSG_PEEK_NOWAIT\n", idClient));
2132 rc = pThis->clientMsgPeek(pClient, hCall, cParms, paParms, false /*fWait*/);
2133 break;
2134 case GUEST_MSG_PEEK_WAIT:
2135 LogFlowFunc(("[Client %RU32] GUEST_MSG_PEEK_WAIT\n", idClient));
2136 rc = pThis->clientMsgPeek(pClient, hCall, cParms, paParms, true /*fWait*/);
2137 break;
2138 case GUEST_MSG_GET:
2139 LogFlowFunc(("[Client %RU32] GUEST_MSG_GET\n", idClient));
2140 rc = pThis->clientMsgGet(pClient, hCall, cParms, paParms);
2141 break;
2142 case GUEST_MSG_CANCEL:
2143 LogFlowFunc(("[Client %RU32] GUEST_MSG_CANCEL\n", idClient));
2144 rc = pThis->clientMsgCancel(pClient, cParms);
2145 break;
2146 case GUEST_MSG_SKIP:
2147 LogFlowFunc(("[Client %RU32] GUEST_MSG_SKIP\n", idClient));
2148 rc = pThis->clientMsgSkip(pClient, hCall, cParms, paParms);
2149 break;
2150 case GUEST_MSG_SESSION_PREPARE:
2151 LogFlowFunc(("[Client %RU32] GUEST_SESSION_PREPARE\n", idClient));
2152 rc = pThis->clientSessionPrepare(pClient, hCall, cParms, paParms);
2153 break;
2154 case GUEST_MSG_SESSION_CANCEL_PREPARED:
2155 LogFlowFunc(("[Client %RU32] GUEST_SESSION_CANCEL_PREPARED\n", idClient));
2156 rc = pThis->clientSessionCancelPrepared(pClient, cParms, paParms);
2157 break;
2158 case GUEST_MSG_SESSION_ACCEPT:
2159 LogFlowFunc(("[Client %RU32] GUEST_SESSION_ACCEPT\n", idClient));
2160 rc = pThis->clientSessionAccept(pClient, hCall, cParms, paParms);
2161 break;
2162 case GUEST_MSG_SESSION_CLOSE:
2163 LogFlowFunc(("[Client %RU32] GUEST_SESSION_CLOSE\n", idClient));
2164 rc = pThis->clientSessionCloseOther(pClient, cParms, paParms);
2165 break;
2166
2167 /*
2168 * Stuff the goes to various main objects:
2169 */
2170 case GUEST_MSG_REPLY:
2171 if (cParms >= 3 && paParms[2].u.uint32 == (uint32_t)VERR_NOT_SUPPORTED)
2172 {
2173 HostMsg *pFirstMsg = RTListGetFirstCpp(&pClient->m_HostMsgList, HostMsg, m_ListEntry);
2174 if (pFirstMsg && pFirstMsg->m_idContext == paParms[0].u.uint32)
2175 pFirstMsg->m_f60BetaHackInPlay = true;
2176 }
2177 RT_FALL_THROUGH();
2178 case GUEST_MSG_PROGRESS_UPDATE:
2179 case GUEST_MSG_SESSION_NOTIFY:
2180 case GUEST_MSG_EXEC_OUTPUT:
2181 case GUEST_MSG_EXEC_STATUS:
2182 case GUEST_MSG_EXEC_INPUT_STATUS:
2183 case GUEST_MSG_EXEC_IO_NOTIFY:
2184 case GUEST_MSG_DIR_NOTIFY:
2185 case GUEST_MSG_FILE_NOTIFY:
2186 LogFlowFunc(("[Client %RU32] %s\n", idClient, GstCtrlGuestMsgToStr((eGuestMsg)u32Function)));
2187 rc = pThis->clientToMain(pClient, u32Function /* Msg */, cParms, paParms);
2188 Assert(rc != VINF_HGCM_ASYNC_EXECUTE);
2189 break;
2190
2191 /*
2192 * The remaining messages are here for compatibility with older Guest Additions:
2193 */
2194 case GUEST_MSG_WAIT:
2195 LogFlowFunc(("[Client %RU32] GUEST_MSG_WAIT\n", idClient));
2196 pThis->clientMsgOldGet(pClient, hCall, cParms, paParms);
2197 rc = VINF_HGCM_ASYNC_EXECUTE;
2198 break;
2199
2200 case GUEST_MSG_SKIP_OLD:
2201 LogFlowFunc(("[Client %RU32] GUEST_MSG_SKIP_OLD\n", idClient));
2202 rc = pThis->clientMsgOldSkip(pClient, hCall, cParms);
2203 break;
2204
2205 case GUEST_MSG_FILTER_SET:
2206 LogFlowFunc(("[Client %RU32] GUEST_MSG_FILTER_SET\n", idClient));
2207 rc = pThis->clientMsgOldFilterSet(pClient, cParms, paParms);
2208 break;
2209
2210 case GUEST_MSG_FILTER_UNSET:
2211 LogFlowFunc(("[Client %RU32] GUEST_MSG_FILTER_UNSET\n", idClient));
2212 rc = VERR_NOT_IMPLEMENTED;
2213 break;
2214
2215 /*
2216 * Anything else shall return invalid function.
2217 * Note! We used to return VINF_SUCCESS for these. See bugref:9313
2218 * and Guest::i_notifyCtrlDispatcher().
2219 */
2220 default:
2221 ASSERT_GUEST_MSG_FAILED(("u32Function=%RU32 (%#x)\n", u32Function, u32Function));
2222 rc = VERR_INVALID_FUNCTION;
2223 break;
2224 }
2225
2226 if (rc != VINF_HGCM_ASYNC_EXECUTE)
2227 {
2228 /* Tell the client that the call is complete (unblocks waiting). */
2229 LogFlowFunc(("[Client %RU32] Calling pfnCallComplete w/ rc=%Rrc\n", idClient, rc));
2230 AssertPtr(pThis->mpHelpers);
2231 pThis->mpHelpers->pfnCallComplete(hCall, rc);
2232 }
2233}
2234
2235
2236/**
2237 * Notifies the host (using low-level HGCM callbacks) about an event
2238 * which was sent from the client.
2239 *
2240 * @returns VBox status code.
2241 * @param u32Function Message ID that occured.
2242 * @param cParms Number of parameters.
2243 * @param paParms Array of parameters.
2244 */
2245int GstCtrlService::hostCallback(uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
2246{
2247 LogFlowFunc(("u32Function=%RU32 (%s), cParms=%ld, paParms=%p\n",
2248 u32Function, GstCtrlGuestMsgToStr((eGuestMsg)u32Function), cParms, paParms));
2249
2250 int rc;
2251 if (mpfnHostCallback)
2252 {
2253 VBOXGUESTCTRLHOSTCALLBACK data = { cParms, paParms };
2254 rc = mpfnHostCallback(mpvHostData, u32Function, &data, sizeof(data));
2255 }
2256 else
2257 rc = VERR_NOT_SUPPORTED;
2258
2259 LogFlowFunc(("Returning rc=%Rrc\n", rc));
2260 return rc;
2261}
2262
2263
2264/**
2265 * Processes a message received from the host side and re-routes it to
2266 * a connect client on the guest.
2267 *
2268 * @returns VBox status code.
2269 * @param idMsg Message ID to process.
2270 * @param cParms Number of parameters.
2271 * @param paParms Array of parameters.
2272 */
2273int GstCtrlService::hostProcessMessage(uint32_t idMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
2274{
2275 /*
2276 * If no client is connected at all we don't buffer any host messages
2277 * and immediately return an error to the host. This avoids the host
2278 * waiting for a response from the guest side in case VBoxService on
2279 * the guest is not running/system is messed up somehow.
2280 */
2281 if (m_ClientStateMap.empty())
2282 {
2283 LogFlow(("GstCtrlService::hostProcessMessage: VERR_NOT_FOUND!\n"));
2284 return VERR_NOT_FOUND;
2285 }
2286
2287 /*
2288 * Create a host message for each destination.
2289 * Note! There is currently only one scenario in which we send a host
2290 * message to two recipients.
2291 */
2292 HostMsg *pHostMsg = new (std::nothrow) HostMsg();
2293 AssertReturn(pHostMsg, VERR_NO_MEMORY);
2294 int rc = pHostMsg->Init(idMsg, cParms, paParms);
2295 if (RT_SUCCESS(rc))
2296 {
2297 uint64_t const fDestinations = pHostMsg->m_idContextAndDst & VBOX_GUESTCTRL_DST_BOTH;
2298 HostMsg *pHostMsg2 = NULL;
2299 if (fDestinations != VBOX_GUESTCTRL_DST_BOTH)
2300 { /* likely */ }
2301 else
2302 {
2303 pHostMsg2 = new (std::nothrow) HostMsg();
2304 if (pHostMsg2)
2305 rc = pHostMsg2->Init(idMsg, cParms, paParms);
2306 else
2307 rc = VERR_NO_MEMORY;
2308 }
2309 if (RT_SUCCESS(rc))
2310 {
2311 LogFlowFunc(("Handling host message m_idContextAndDst=%#RX64, idMsg=%RU32, cParms=%RU32, paParms=%p, cClients=%zu\n",
2312 pHostMsg->m_idContextAndDst, idMsg, cParms, paParms, m_ClientStateMap.size()));
2313
2314 /*
2315 * Find the message destination and post it to the client. If the
2316 * session ID doesn't match any particular client it goes to the master.
2317 */
2318 AssertMsg(!m_ClientStateMap.empty(), ("Client state map is empty when it should not be!\n"));
2319
2320 /* Dispatch to the session. */
2321 if (fDestinations & VBOX_GUESTCTRL_DST_SESSION)
2322 {
2323 uint32_t const idSession = VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(pHostMsg->m_idContext);
2324 ClientStateMap::iterator It = m_SessionIdMap.find(idSession);
2325 if (It != m_SessionIdMap.end())
2326 {
2327 ClientState *pClient = It->second;
2328 Assert(pClient->m_idSession == idSession);
2329 RTListAppend(&pClient->m_HostMsgList, &pHostMsg->m_ListEntry);
2330 pHostMsg = pHostMsg2;
2331 pHostMsg2 = NULL;
2332
2333 int rc2 = pClient->Wakeup();
2334 LogFlowFunc(("Woke up client ID=%RU32 -> rc=%Rrc\n", pClient->m_idClient, rc2));
2335 RT_NOREF(rc2);
2336 rc = VINF_SUCCESS;
2337 }
2338 else
2339 {
2340 LogFunc(("No client with session ID %u was found! (idMsg=%d %s)\n",
2341 idSession, idMsg, GstCtrlHostMsgtoStr((eHostMsg)idMsg)));
2342 rc = !(fDestinations & VBOX_GUESTCTRL_DST_ROOT_SVC) ? VERR_NOT_FOUND : VWRN_NOT_FOUND;
2343 }
2344 }
2345
2346 /* Does the message go to the root service? */
2347 if ( (fDestinations & VBOX_GUESTCTRL_DST_ROOT_SVC)
2348 && RT_SUCCESS(rc))
2349 {
2350 Assert(pHostMsg);
2351 if (m_pMasterClient)
2352 {
2353 RTListAppend(&m_pMasterClient->m_HostMsgList, &pHostMsg->m_ListEntry);
2354 pHostMsg = NULL;
2355
2356 int rc2 = m_pMasterClient->Wakeup();
2357 LogFlowFunc(("Woke up client ID=%RU32 (master) -> rc=%Rrc\n", m_pMasterClient->m_idClient, rc2));
2358 NOREF(rc2);
2359 }
2360 else
2361 rc = VERR_NOT_FOUND;
2362 }
2363 }
2364
2365 /* Drop unset messages. */
2366 if (pHostMsg2)
2367 pHostMsg2->Delete();
2368 }
2369 if (pHostMsg)
2370 pHostMsg->Delete();
2371
2372 if (RT_FAILURE(rc))
2373 LogFunc(("Failed %Rrc (idMsg=%u, cParms=%u)\n", rc, idMsg, cParms));
2374 return rc;
2375}
2376
2377
2378/**
2379 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnHostCall,
2380 * Wraps to the hostProcessMessage() member function.}
2381 */
2382/*static*/ DECLCALLBACK(int)
2383GstCtrlService::svcHostCall(void *pvService, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
2384{
2385 AssertLogRelReturn(RT_VALID_PTR(pvService), VERR_INVALID_PARAMETER);
2386 SELF *pThis = reinterpret_cast<SELF *>(pvService);
2387 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2388
2389 LogFlowFunc(("u32Function=%RU32, cParms=%RU32, paParms=0x%p\n", u32Function, cParms, paParms));
2390 AssertReturn(u32Function != HOST_MSG_CANCEL_PENDING_WAITS, VERR_INVALID_FUNCTION);
2391 return pThis->hostProcessMessage(u32Function, cParms, paParms);
2392}
2393
2394
2395
2396
2397/**
2398 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnSaveState}
2399 */
2400/*static*/ DECLCALLBACK(int)
2401GstCtrlService::svcSaveState(void *pvService, uint32_t idClient, void *pvClient, PSSMHANDLE pSSM)
2402{
2403 RT_NOREF(pvClient);
2404 SELF *pThis = reinterpret_cast<SELF *>(pvService);
2405 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2406
2407 /* Note! We don't need to save the idSession here because it's only used
2408 for sessions and the sessions are not persistent across a state
2409 save/restore. The Main objects aren't there. Clients shuts down.
2410 Only the root service survives, so remember who that is and its mode. */
2411
2412 SSMR3PutU32(pSSM, 1);
2413 SSMR3PutBool(pSSM, pThis->m_fLegacyMode);
2414 return SSMR3PutBool(pSSM, idClient == pThis->m_idMasterClient);
2415}
2416
2417
2418/**
2419 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnLoadState}
2420 */
2421/*static*/ DECLCALLBACK(int)
2422GstCtrlService::svcLoadState(void *pvService, uint32_t idClient, void *pvClient, PSSMHANDLE pSSM, uint32_t uVersion)
2423{
2424 SELF *pThis = reinterpret_cast<SELF *>(pvService);
2425 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2426 ClientState *pClient = reinterpret_cast<ClientState *>(pvClient);
2427 AssertReturn(pClient, VERR_INVALID_CLIENT_ID);
2428 Assert(pClient->m_idClient == idClient);
2429
2430 if (uVersion >= HGCM_SAVED_STATE_VERSION)
2431 {
2432 uint32_t uSubVersion;
2433 int rc = SSMR3GetU32(pSSM, &uSubVersion);
2434 AssertRCReturn(rc, rc);
2435 if (uSubVersion != 1)
2436 return SSMR3SetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
2437 "sub version %u, expected 1\n", uSubVersion);
2438 bool fLegacyMode;
2439 rc = SSMR3GetBool(pSSM, &fLegacyMode);
2440 AssertRCReturn(rc, rc);
2441 pThis->m_fLegacyMode = fLegacyMode;
2442
2443 bool fIsMaster;
2444 rc = SSMR3GetBool(pSSM, &fIsMaster);
2445 AssertRCReturn(rc, rc);
2446
2447 pClient->m_fIsMaster = fIsMaster;
2448 if (fIsMaster)
2449 {
2450 pThis->m_pMasterClient = pClient;
2451 pThis->m_idMasterClient = idClient;
2452 }
2453 }
2454 else
2455 {
2456 /*
2457 * For old saved states we have to guess at who should be the master.
2458 * Given how HGCMService::CreateAndConnectClient and associates manage
2459 * and saves the client, the first client connecting will be restored
2460 * first. The only time this might go wrong if the there are zombie
2461 * VBoxService session processes in the restored guest, and I don't
2462 * we need to care too much about that scenario.
2463 *
2464 * Given how HGCM first re-connects the clients before this function
2465 * gets called, there isn't anything we need to do here it turns out. :-)
2466 */
2467 }
2468 pClient->m_fRestored = true;
2469 return VINF_SUCCESS;
2470}
2471
2472
2473/**
2474 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnRegisterExtension,
2475 * Installs a host callback for notifications of property changes.}
2476 */
2477/*static*/ DECLCALLBACK(int) GstCtrlService::svcRegisterExtension(void *pvService, PFNHGCMSVCEXT pfnExtension, void *pvExtension)
2478{
2479 SELF *pThis = reinterpret_cast<SELF *>(pvService);
2480 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2481 AssertPtrNullReturn(pfnExtension, VERR_INVALID_POINTER);
2482
2483 pThis->mpfnHostCallback = pfnExtension;
2484 pThis->mpvHostData = pvExtension;
2485 return VINF_SUCCESS;
2486}
2487
2488
2489/**
2490 * @copydoc FNVBOXHGCMSVCLOAD
2491 */
2492extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *pTable)
2493{
2494 int rc = VINF_SUCCESS;
2495
2496 LogFlowFunc(("pTable=%p\n", pTable));
2497
2498 if (!RT_VALID_PTR(pTable))
2499 rc = VERR_INVALID_PARAMETER;
2500 else
2501 {
2502 LogFlowFunc(("pTable->cbSize=%d, pTable->u32Version=0x%08X\n", pTable->cbSize, pTable->u32Version));
2503
2504 if ( pTable->cbSize != sizeof (VBOXHGCMSVCFNTABLE)
2505 || pTable->u32Version != VBOX_HGCM_SVC_VERSION)
2506 {
2507 rc = VERR_VERSION_MISMATCH;
2508 }
2509 else
2510 {
2511 GstCtrlService *pService = NULL;
2512 /* No exceptions may propagate outside. */
2513 try
2514 {
2515 pService = new GstCtrlService(pTable->pHelpers);
2516 }
2517 catch (int rcThrown)
2518 {
2519 rc = rcThrown;
2520 }
2521 catch(std::bad_alloc &)
2522 {
2523 rc = VERR_NO_MEMORY;
2524 }
2525
2526 if (RT_SUCCESS(rc))
2527 {
2528 /*
2529 * We don't need an additional client data area on the host,
2530 * because we're a class which can have members for that :-).
2531 */
2532 pTable->cbClient = sizeof(ClientState);
2533
2534 /* Limit pending calls to 8 pending per connection (doubt we need more than
2535 one). Map legacy clients to the root and limit kernel to 1. Use defaults
2536 for root and user clients. */
2537 for (uintptr_t i = 0; i < RT_ELEMENTS(pTable->acMaxClients); i++)
2538 pTable->acMaxCallsPerClient[i] = 8;
2539
2540 pTable->idxLegacyClientCategory = HGCM_CLIENT_CATEGORY_ROOT;
2541 pTable->acMaxClients[HGCM_CLIENT_CATEGORY_KERNEL] = 1;
2542
2543 /* Register functions. */
2544 pTable->pfnUnload = GstCtrlService::svcUnload;
2545 pTable->pfnConnect = GstCtrlService::svcConnect;
2546 pTable->pfnDisconnect = GstCtrlService::svcDisconnect;
2547 pTable->pfnCall = GstCtrlService::svcCall;
2548 pTable->pfnHostCall = GstCtrlService::svcHostCall;
2549 pTable->pfnSaveState = GstCtrlService::svcSaveState;
2550 pTable->pfnLoadState = GstCtrlService::svcLoadState;
2551 pTable->pfnRegisterExtension = GstCtrlService::svcRegisterExtension;
2552 pTable->pfnNotify = NULL;
2553
2554 /* Service specific initialization. */
2555 pTable->pvService = pService;
2556 }
2557 else
2558 {
2559 if (pService)
2560 {
2561 delete pService;
2562 pService = NULL;
2563 }
2564 }
2565 }
2566 }
2567
2568 LogFlowFunc(("Returning %Rrc\n", rc));
2569 return rc;
2570}
2571
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