VirtualBox

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

Last change on this file since 99844 was 99262, checked in by vboxsync, 21 months ago

Guest Control: Implements IGuestSession::fsQueryInfo() and IGuestSession::fsQueryFreeSpace(). bugref:10414

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