VirtualBox

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

Last change on this file since 98110 was 98103, checked in by vboxsync, 23 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 100.2 KB
Line 
1/* $Id: VBoxGuestControlSvc.cpp 98103 2023-01-17 14:15:46Z 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_ARGV0;
955
956
957/**
958 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnUnload,
959 * Simply deletes the GstCtrlService object}
960 */
961/*static*/ DECLCALLBACK(int)
962GstCtrlService::svcUnload(void *pvService)
963{
964 AssertLogRelReturn(RT_VALID_PTR(pvService), VERR_INVALID_PARAMETER);
965 SELF *pThis = reinterpret_cast<SELF *>(pvService);
966 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
967
968 delete pThis;
969
970 return VINF_SUCCESS;
971}
972
973
974
975/**
976 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnConnect,
977 * Initializes the state for a new client.}
978 */
979/*static*/ DECLCALLBACK(int)
980GstCtrlService::svcConnect(void *pvService, uint32_t idClient, void *pvClient, uint32_t fRequestor, bool fRestoring)
981{
982 LogFlowFunc(("[Client %RU32] Connected\n", idClient));
983
984 RT_NOREF(fRestoring, pvClient);
985 AssertLogRelReturn(RT_VALID_PTR(pvService), VERR_INVALID_PARAMETER);
986 SELF *pThis = reinterpret_cast<SELF *>(pvService);
987 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
988
989 AssertMsg(pThis->m_ClientStateMap.find(idClient) == pThis->m_ClientStateMap.end(),
990 ("Client with ID=%RU32 already connected when it should not\n", idClient));
991
992 /*
993 * Create client state.
994 */
995 ClientState *pClient = NULL;
996 try
997 {
998 pClient = new (pvClient) ClientState(pThis->mpHelpers, idClient);
999 pThis->m_ClientStateMap[idClient] = pClient;
1000 }
1001 catch (std::bad_alloc &)
1002 {
1003 if (pClient)
1004 pClient->~ClientState();
1005 return VERR_NO_MEMORY;
1006 }
1007
1008 /*
1009 * For legacy compatibility reasons we have to pick a master client at some
1010 * point, so if the /dev/vboxguest requirements checks out we pick the first
1011 * one through the door.
1012 */
1013/** @todo make picking the master more dynamic/flexible? */
1014 if ( pThis->m_fLegacyMode
1015 && pThis->m_idMasterClient == UINT32_MAX)
1016 {
1017 if ( fRequestor == VMMDEV_REQUESTOR_LEGACY
1018 || !(fRequestor & VMMDEV_REQUESTOR_USER_DEVICE))
1019 {
1020 LogFunc(("Picking %u as master for now.\n", idClient));
1021 pThis->m_pMasterClient = pClient;
1022 pThis->m_idMasterClient = idClient;
1023 pClient->m_fIsMaster = true;
1024 }
1025 }
1026
1027 return VINF_SUCCESS;
1028}
1029
1030
1031/**
1032 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnConnect,
1033 * Handles a client which disconnected.}
1034 *
1035 * This functiond does some internal cleanup as well as sends notifications to
1036 * the host so that the host can do the same (if required).
1037 */
1038/*static*/ DECLCALLBACK(int)
1039GstCtrlService::svcDisconnect(void *pvService, uint32_t idClient, void *pvClient)
1040{
1041 SELF *pThis = reinterpret_cast<SELF *>(pvService);
1042 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1043 ClientState *pClient = reinterpret_cast<ClientState *>(pvClient);
1044 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
1045 LogFlowFunc(("[Client %RU32] Disconnected (%zu clients total)\n", idClient, pThis->m_ClientStateMap.size()));
1046
1047 /*
1048 * Cancel all pending host messages, replying with GUEST_DISCONNECTED if final recipient.
1049 */
1050 HostMsg *pCurMsg, *pNextMsg;
1051 RTListForEachSafeCpp(&pClient->m_HostMsgList, pCurMsg, pNextMsg, HostMsg, m_ListEntry)
1052 {
1053 RTListNodeRemove(&pCurMsg->m_ListEntry);
1054
1055 VBOXHGCMSVCPARM Parm;
1056 HGCMSvcSetU32(&Parm, pCurMsg->m_idContext);
1057 int rc2 = pThis->hostCallback(GUEST_MSG_DISCONNECTED, 1, &Parm);
1058 LogFlowFunc(("Cancelled host message %u (%s) with idContext=%#x -> %Rrc\n",
1059 pCurMsg->mType, GstCtrlHostMsgtoStr((eHostMsg)pCurMsg->mType), pCurMsg->m_idContext, rc2));
1060 RT_NOREF(rc2);
1061
1062 pCurMsg->Delete();
1063 }
1064
1065 /*
1066 * If it's the master disconnecting, we need to reset related globals.
1067 */
1068 if (idClient == pThis->m_idMasterClient)
1069 {
1070 pThis->m_pMasterClient = NULL;
1071 pThis->m_idMasterClient = UINT32_MAX;
1072
1073 GstCtrlPreparedSession *pCur, *pNext;
1074 RTListForEachSafe(&pThis->m_PreparedSessions, pCur, pNext, GstCtrlPreparedSession, ListEntry)
1075 {
1076 RTListNodeRemove(&pCur->ListEntry);
1077 RTMemFree(pCur);
1078 }
1079 pThis->m_cPreparedSessions = 0;
1080
1081 /* Make sure that the host gets notified about still associated guest sessions going down.
1082 *
1083 * Some guest OSes (like OL8) do reboot / shut down quite abruptly so that
1084 * VBoxService does not have the chance to do so instead.
1085 *
1086 * Note: We do this only when the master disconnects as a last meassure, as this otherwise
1087 * would overwrite formerly sent session statuses on the host.
1088 */
1089 ClientStateMap::const_iterator itClientState = pThis->m_SessionIdMap.begin();
1090 while (itClientState != pThis->m_SessionIdMap.end())
1091 {
1092 VBOXHGCMSVCPARM aParms[4];
1093 HGCMSvcSetU32(&aParms[0], VBOX_GUESTCTRL_CONTEXTID_MAKE(pCur->idSession, 0 /* uObject */, 0 /* uCount */));
1094 HGCMSvcSetU32(&aParms[1], GUEST_SESSION_NOTIFYTYPE_DWN); /* type */
1095 HGCMSvcSetU32(&aParms[2], VINF_SUCCESS); /* result */
1096
1097 int rc2 = pThis->hostCallback(GUEST_MSG_SESSION_NOTIFY, 3, aParms);
1098 LogFlowFunc(("Notified host about session ID=%RU32 going down -> %Rrc\n", pClient->m_idSession, rc2));
1099 RT_NOREF(rc2);
1100
1101 ++itClientState;
1102 /* Note: Don't erase the client state -- this will be done when the actual client is disconnecting. */
1103 }
1104 }
1105 else
1106 Assert(pClient != pThis->m_pMasterClient);
1107
1108 /*
1109 * Delete the client state.
1110 */
1111 pThis->m_ClientStateMap.erase(idClient);
1112 if (pClient->m_idSession != UINT32_MAX)
1113 pThis->m_SessionIdMap.erase(pClient->m_idSession);
1114 pClient->~ClientState();
1115
1116 if (pThis->m_ClientStateMap.empty())
1117 pThis->m_fLegacyMode = true;
1118
1119 return VINF_SUCCESS;
1120}
1121
1122
1123/**
1124 * A client asks for the next message to process.
1125 *
1126 * This either fills in a pending host message into the client's parameter space
1127 * or defers the guest call until we have something from the host.
1128 *
1129 * @returns VBox status code.
1130 * @param pClient The client state.
1131 * @param hCall The client's call handle.
1132 * @param cParms Number of parameters.
1133 * @param paParms Array of parameters.
1134 */
1135int GstCtrlService::clientMsgOldGet(ClientState *pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1136{
1137 ASSERT_GUEST(pClient->m_idSession != UINT32_MAX || pClient->m_fIsMaster || pClient->m_fRestored);
1138
1139 /* Use the current (inbound) connection. */
1140 ClientRequest thisCon;
1141 thisCon.mHandle = hCall;
1142 thisCon.mNumParms = cParms;
1143 thisCon.mParms = paParms;
1144
1145 return pClient->OldRunCurrent(&thisCon);
1146}
1147
1148
1149/**
1150 * Implements GUEST_MAKE_ME_MASTER.
1151 *
1152 * @returns VBox status code.
1153 * @retval VINF_HGCM_ASYNC_EXECUTE on success (we complete the message here).
1154 * @retval VERR_ACCESS_DENIED if not using main VBoxGuest device not
1155 * @retval VERR_RESOURCE_BUSY if there is already a master.
1156 * @retval VERR_VERSION_MISMATCH if VBoxGuest didn't supply requestor info.
1157 * @retval VERR_WRONG_PARAMETER_COUNT
1158 *
1159 * @param pClient The client state.
1160 * @param hCall The client's call handle.
1161 * @param cParms Number of parameters.
1162 */
1163int GstCtrlService::clientMakeMeMaster(ClientState *pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms)
1164{
1165 /*
1166 * Validate the request.
1167 */
1168 ASSERT_GUEST_RETURN(cParms == 0, VERR_WRONG_PARAMETER_COUNT);
1169
1170 uint32_t fRequestor = mpHelpers->pfnGetRequestor(hCall);
1171 /* The next assertion triggers upgrading GAs on some linux guests. Problem is that VBoxService is
1172 restarted after installation but the kernel module hasn't been reloaded, so things are out
1173 of wack. Just reboot. */
1174 ASSERT_GUEST_LOGREL_MSG_RETURN(fRequestor != VMMDEV_REQUESTOR_LEGACY,
1175 ("Guest is using outdated VBoxGuest w/o requestor support.\n"
1176 "Please update guest additions (or restart guest if you just did)!\n"),
1177 VERR_VERSION_MISMATCH);
1178 ASSERT_GUEST_LOGREL_MSG_RETURN(!(fRequestor & VMMDEV_REQUESTOR_USER_DEVICE), ("fRequestor=%#x\n", fRequestor),
1179 VERR_ACCESS_DENIED);
1180
1181 /*
1182 * Do the work.
1183 */
1184 ASSERT_GUEST_MSG_RETURN(m_idMasterClient == pClient->m_idClient || m_idMasterClient == UINT32_MAX,
1185 ("Already have master session %RU32, refusing %RU32.\n", m_idMasterClient, pClient->m_idClient),
1186 VERR_RESOURCE_BUSY);
1187 int rc = mpHelpers->pfnCallComplete(hCall, VINF_SUCCESS);
1188 if (RT_SUCCESS(rc))
1189 {
1190 m_pMasterClient = pClient;
1191 m_idMasterClient = pClient->m_idClient;
1192 m_fLegacyMode = false;
1193 pClient->m_fIsMaster = true;
1194 Log(("[Client %RU32] is master.\n", pClient->m_idClient));
1195 }
1196 else
1197 LogFunc(("pfnCallComplete -> %Rrc\n", rc));
1198
1199 return VINF_HGCM_ASYNC_EXECUTE;
1200}
1201
1202
1203/**
1204 * Implements GUEST_MSG_REPORT_FEATURES.
1205 *
1206 * @returns VBox status code.
1207 * @retval VINF_HGCM_ASYNC_EXECUTE on success (we complete the message here).
1208 * @retval VERR_ACCESS_DENIED if not master
1209 * @retval VERR_INVALID_PARAMETER if bit 63 in the 2nd parameter isn't set.
1210 * @retval VERR_WRONG_PARAMETER_COUNT
1211 *
1212 * @param pClient The client state.
1213 * @param hCall The client's call handle.
1214 * @param cParms Number of parameters.
1215 * @param paParms Array of parameters.
1216 */
1217int GstCtrlService::clientReportFeatures(ClientState *pClient, VBOXHGCMCALLHANDLE hCall,
1218 uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1219{
1220 /*
1221 * Validate the request.
1222 */
1223 ASSERT_GUEST_RETURN(cParms == 2, VERR_WRONG_PARAMETER_COUNT);
1224 ASSERT_GUEST_RETURN(paParms[0].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE);
1225 uint64_t const fFeatures0 = paParms[0].u.uint64;
1226 ASSERT_GUEST_RETURN(paParms[1].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE);
1227 uint64_t const fFeatures1 = paParms[1].u.uint64;
1228 ASSERT_GUEST_RETURN(fFeatures1 & VBOX_GUESTCTRL_GF_1_MUST_BE_ONE, VERR_INVALID_PARAMETER);
1229
1230 ASSERT_GUEST_RETURN(pClient->m_fIsMaster, VERR_ACCESS_DENIED);
1231
1232 /*
1233 * Do the work.
1234 */
1235 VBOXHGCMSVCPARM aCopyForMain[2] = { paParms[0], paParms[1] };
1236
1237 paParms[0].u.uint64 = g_fGstCtrlHostFeatures0;
1238 paParms[1].u.uint64 = 0;
1239
1240 int rc = mpHelpers->pfnCallComplete(hCall, VINF_SUCCESS);
1241 if (RT_SUCCESS(rc))
1242 {
1243 m_fGuestFeatures0 = fFeatures0;
1244 m_fGuestFeatures1 = fFeatures1;
1245 Log(("[Client %RU32] reported features: %#RX64 %#RX64\n", pClient->m_idClient, fFeatures0, fFeatures1));
1246
1247 /*
1248 * Forward the info to main.
1249 */
1250 hostCallback(GUEST_MSG_REPORT_FEATURES, RT_ELEMENTS(aCopyForMain), aCopyForMain);
1251 }
1252 else
1253 LogFunc(("pfnCallComplete -> %Rrc\n", rc));
1254
1255 return VINF_HGCM_ASYNC_EXECUTE;
1256}
1257
1258
1259/**
1260 * Implements GUEST_MSG_QUERY_FEATURES.
1261 *
1262 * @returns VBox status code.
1263 * @retval VINF_HGCM_ASYNC_EXECUTE on success (we complete the message here).
1264 * @retval VERR_WRONG_PARAMETER_COUNT
1265 *
1266 * @param pClient The client state.
1267 * @param hCall The client's call handle.
1268 * @param cParms Number of parameters.
1269 * @param paParms Array of parameters.
1270 */
1271int GstCtrlService::clientQueryFeatures(ClientState *pClient,
1272 VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1273{
1274 RT_NOREF(pClient);
1275
1276 /*
1277 * Validate the request.
1278 */
1279 ASSERT_GUEST_RETURN(cParms == 2, VERR_WRONG_PARAMETER_COUNT);
1280 ASSERT_GUEST_RETURN(paParms[0].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE);
1281 ASSERT_GUEST_RETURN(paParms[1].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE);
1282 ASSERT_GUEST(paParms[1].u.uint64 & RT_BIT_64(63));
1283
1284 /*
1285 * Do the work.
1286 */
1287 paParms[0].u.uint64 = g_fGstCtrlHostFeatures0;
1288 paParms[1].u.uint64 = 0;
1289 int rc = mpHelpers->pfnCallComplete(hCall, VINF_SUCCESS);
1290 if (RT_SUCCESS(rc))
1291 {
1292 Log(("[Client %RU32] query features: %#RX64 0\n", pClient->m_idClient, g_fGstCtrlHostFeatures0));
1293 }
1294 else
1295 LogFunc(("pfnCallComplete -> %Rrc\n", rc));
1296
1297 return VINF_HGCM_ASYNC_EXECUTE;
1298}
1299
1300
1301/**
1302 * Implements GUEST_MSG_PEEK_WAIT and GUEST_MSG_PEEK_NOWAIT.
1303 *
1304 * @returns VBox status code.
1305 * @retval VINF_SUCCESS if a message was pending and is being returned.
1306 * @retval VERR_TRY_AGAIN if no message pending and not blocking.
1307 * @retval VERR_RESOURCE_BUSY if another read already made a waiting call.
1308 * @retval VINF_HGCM_ASYNC_EXECUTE if message wait is pending.
1309 *
1310 * @param pClient The client state.
1311 * @param hCall The client's call handle.
1312 * @param cParms Number of parameters.
1313 * @param paParms Array of parameters.
1314 * @param fWait Set if we should wait for a message, clear if to return
1315 * immediately.
1316 */
1317int GstCtrlService::clientMsgPeek(ClientState *pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool fWait)
1318{
1319 /*
1320 * Validate the request.
1321 */
1322 ASSERT_GUEST_MSG_RETURN(cParms >= 2, ("cParms=%u!\n", cParms), VERR_WRONG_PARAMETER_COUNT);
1323
1324 uint64_t idRestoreCheck = 0;
1325 uint32_t i = 0;
1326 if (paParms[i].type == VBOX_HGCM_SVC_PARM_64BIT)
1327 {
1328 idRestoreCheck = paParms[0].u.uint64;
1329 paParms[0].u.uint64 = 0;
1330 i++;
1331 }
1332 for (; i < cParms; i++)
1333 {
1334 ASSERT_GUEST_MSG_RETURN(paParms[i].type == VBOX_HGCM_SVC_PARM_32BIT, ("#%u type=%u\n", i, paParms[i].type),
1335 VERR_WRONG_PARAMETER_TYPE);
1336 paParms[i].u.uint32 = 0;
1337 }
1338
1339 /*
1340 * Check restore session ID.
1341 */
1342 if (idRestoreCheck != 0)
1343 {
1344 uint64_t idRestore = mpHelpers->pfnGetVMMDevSessionId(mpHelpers);
1345 if (idRestoreCheck != idRestore)
1346 {
1347 paParms[0].u.uint64 = idRestore;
1348 LogFlowFunc(("[Client %RU32] GUEST_MSG_PEEK_XXXX -> VERR_VM_RESTORED (%#RX64 -> %#RX64)\n",
1349 pClient->m_idClient, idRestoreCheck, idRestore));
1350 return VERR_VM_RESTORED;
1351 }
1352 Assert(!mpHelpers->pfnIsCallRestored(hCall));
1353 }
1354
1355 /*
1356 * Return information about the first message if one is pending in the list.
1357 */
1358 HostMsg *pFirstMsg = RTListGetFirstCpp(&pClient->m_HostMsgList, HostMsg, m_ListEntry);
1359 if (pFirstMsg)
1360 {
1361 pFirstMsg->setPeekReturn(paParms, cParms);
1362 LogFlowFunc(("[Client %RU32] GUEST_MSG_PEEK_XXXX -> VINF_SUCCESS (idMsg=%u (%s), cParms=%u)\n",
1363 pClient->m_idClient, pFirstMsg->mType, GstCtrlHostMsgtoStr((eHostMsg)pFirstMsg->mType), pFirstMsg->mParmCount));
1364 return VINF_SUCCESS;
1365 }
1366
1367 /*
1368 * If we cannot wait, fail the call.
1369 */
1370 if (!fWait)
1371 {
1372 LogFlowFunc(("[Client %RU32] GUEST_MSG_PEEK_NOWAIT -> VERR_TRY_AGAIN\n", pClient->m_idClient));
1373 return VERR_TRY_AGAIN;
1374 }
1375
1376 /*
1377 * Wait for the host to queue a message for this client.
1378 */
1379 ASSERT_GUEST_MSG_RETURN(pClient->m_enmPendingMsg == 0, ("Already pending! (idClient=%RU32)\n", pClient->m_idClient),
1380 VERR_RESOURCE_BUSY);
1381 pClient->m_PendingReq.mHandle = hCall;
1382 pClient->m_PendingReq.mNumParms = cParms;
1383 pClient->m_PendingReq.mParms = paParms;
1384 pClient->m_enmPendingMsg = GUEST_MSG_PEEK_WAIT;
1385 LogFlowFunc(("[Client %RU32] Is now in pending mode...\n", pClient->m_idClient));
1386 return VINF_HGCM_ASYNC_EXECUTE;
1387}
1388
1389/**
1390 * Implements GUEST_MSG_GET.
1391 *
1392 * @returns VBox status code.
1393 * @retval VINF_SUCCESS if message retrieved and removed from the pending queue.
1394 * @retval VERR_TRY_AGAIN if no message pending.
1395 * @retval VERR_BUFFER_OVERFLOW if a parmeter buffer is too small. The buffer
1396 * size was updated to reflect the required size, though this isn't yet
1397 * forwarded to the guest. (The guest is better of using peek with
1398 * parameter count + 2 parameters to get the sizes.)
1399 * @retval VERR_MISMATCH if the incoming message ID does not match the pending.
1400 * @retval VINF_HGCM_ASYNC_EXECUTE if message was completed already.
1401 *
1402 * @param pClient The client state.
1403 * @param hCall The client's call handle.
1404 * @param cParms Number of parameters.
1405 * @param paParms Array of parameters.
1406 */
1407int GstCtrlService::clientMsgGet(ClientState *pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1408{
1409 /*
1410 * Validate the request.
1411 *
1412 * The weird first parameter logic is due to GUEST_MSG_WAIT compatibility
1413 * (don't want to rewrite all the message structures).
1414 */
1415 uint32_t const idMsgExpected = cParms > 0 && paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT ? paParms[0].u.uint32
1416 : cParms > 0 && paParms[0].type == VBOX_HGCM_SVC_PARM_64BIT ? paParms[0].u.uint64
1417 : UINT32_MAX;
1418
1419 /*
1420 * Return information about the first message if one is pending in the list.
1421 */
1422 HostMsg *pFirstMsg = RTListGetFirstCpp(&pClient->m_HostMsgList, HostMsg, m_ListEntry);
1423 if (pFirstMsg)
1424 {
1425
1426 ASSERT_GUEST_MSG_RETURN(pFirstMsg->mType == idMsgExpected || idMsgExpected == UINT32_MAX,
1427 ("idMsg=%u (%s) cParms=%u, caller expected %u (%s) and %u\n",
1428 pFirstMsg->mType, GstCtrlHostMsgtoStr((eHostMsg)pFirstMsg->mType), pFirstMsg->mParmCount,
1429 idMsgExpected, GstCtrlHostMsgtoStr((eHostMsg)idMsgExpected), cParms),
1430 VERR_MISMATCH);
1431 ASSERT_GUEST_MSG_RETURN(pFirstMsg->mParmCount == cParms,
1432 ("idMsg=%u (%s) cParms=%u, caller expected %u (%s) and %u\n",
1433 pFirstMsg->mType, GstCtrlHostMsgtoStr((eHostMsg)pFirstMsg->mType), pFirstMsg->mParmCount,
1434 idMsgExpected, GstCtrlHostMsgtoStr((eHostMsg)idMsgExpected), cParms),
1435 VERR_WRONG_PARAMETER_COUNT);
1436
1437 /* Check the parameter types. */
1438 for (uint32_t i = 0; i < cParms; i++)
1439 ASSERT_GUEST_MSG_RETURN(pFirstMsg->mpParms[i].type == paParms[i].type,
1440 ("param #%u: type %u, caller expected %u (idMsg=%u %s)\n", i, pFirstMsg->mpParms[i].type,
1441 paParms[i].type, pFirstMsg->mType, GstCtrlHostMsgtoStr((eHostMsg)pFirstMsg->mType)),
1442 VERR_WRONG_PARAMETER_TYPE);
1443
1444 /*
1445 * Copy out the parameters.
1446 *
1447 * No assertions on buffer overflows, and keep going till the end so we can
1448 * communicate all the required buffer sizes.
1449 */
1450 int rc = VINF_SUCCESS;
1451 for (uint32_t i = 0; i < cParms; i++)
1452 switch (pFirstMsg->mpParms[i].type)
1453 {
1454 case VBOX_HGCM_SVC_PARM_32BIT:
1455 paParms[i].u.uint32 = pFirstMsg->mpParms[i].u.uint32;
1456 break;
1457
1458 case VBOX_HGCM_SVC_PARM_64BIT:
1459 paParms[i].u.uint64 = pFirstMsg->mpParms[i].u.uint64;
1460 break;
1461
1462 case VBOX_HGCM_SVC_PARM_PTR:
1463 {
1464 uint32_t const cbSrc = pFirstMsg->mpParms[i].u.pointer.size;
1465 uint32_t const cbDst = paParms[i].u.pointer.size;
1466 paParms[i].u.pointer.size = cbSrc; /** @todo Check if this is safe in other layers...
1467 * Update: Safe, yes, but VMMDevHGCM doesn't pass it along. */
1468 if (cbSrc <= cbDst)
1469 memcpy(paParms[i].u.pointer.addr, pFirstMsg->mpParms[i].u.pointer.addr, cbSrc);
1470 else
1471 rc = VERR_BUFFER_OVERFLOW;
1472 break;
1473 }
1474
1475 default:
1476 AssertMsgFailed(("#%u: %u\n", i, pFirstMsg->mpParms[i].type));
1477 rc = VERR_INTERNAL_ERROR;
1478 break;
1479 }
1480 if (RT_SUCCESS(rc))
1481 {
1482 /*
1483 * Complete the message and remove the pending message unless the
1484 * guest raced us and cancelled this call in the meantime.
1485 */
1486 AssertPtr(mpHelpers);
1487 rc = mpHelpers->pfnCallComplete(hCall, rc);
1488 if (rc != VERR_CANCELLED)
1489 {
1490 RTListNodeRemove(&pFirstMsg->m_ListEntry);
1491 pFirstMsg->Delete();
1492 }
1493 else
1494 LogFunc(("pfnCallComplete -> %Rrc\n", rc));
1495 return VINF_HGCM_ASYNC_EXECUTE; /* The caller must not complete it. */
1496 }
1497 return rc;
1498 }
1499
1500 paParms[0].u.uint32 = 0;
1501 paParms[1].u.uint32 = 0;
1502 LogFlowFunc(("[Client %RU32] GUEST_MSG_GET -> VERR_TRY_AGAIN\n", pClient->m_idClient));
1503 return VERR_TRY_AGAIN;
1504}
1505
1506/**
1507 * Implements GUEST_MSG_CANCEL.
1508 *
1509 * @returns VBox status code.
1510 * @retval VINF_SUCCESS if cancelled any calls.
1511 * @retval VWRN_NOT_FOUND if no callers.
1512 * @retval VINF_HGCM_ASYNC_EXECUTE if message wait is pending.
1513 *
1514 * @param pClient The client state.
1515 * @param cParms Number of parameters.
1516 */
1517int GstCtrlService::clientMsgCancel(ClientState *pClient, uint32_t cParms)
1518{
1519 /*
1520 * Validate the request.
1521 */
1522 ASSERT_GUEST_MSG_RETURN(cParms == 0, ("cParms=%u!\n", cParms), VERR_WRONG_PARAMETER_COUNT);
1523
1524 /*
1525 * Execute.
1526 */
1527 if (pClient->m_enmPendingMsg != 0)
1528 {
1529 pClient->CancelWaiting();
1530 return VINF_SUCCESS;
1531 }
1532 return VWRN_NOT_FOUND;
1533}
1534
1535
1536/**
1537 * Implements GUEST_MSG_SKIP.
1538 *
1539 * @returns VBox status code.
1540 * @retval VINF_HGCM_ASYNC_EXECUTE on success as we complete the message.
1541 * @retval VERR_NOT_FOUND if no message pending.
1542 *
1543 * @param pClient The client state.
1544 * @param hCall The call handle for completing it.
1545 * @param cParms Number of parameters.
1546 * @param paParms The parameters.
1547 */
1548int GstCtrlService::clientMsgSkip(ClientState *pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1549{
1550 /*
1551 * Validate the call.
1552 */
1553 ASSERT_GUEST_RETURN(cParms <= 2, VERR_WRONG_PARAMETER_COUNT);
1554
1555 int32_t rcSkip = VERR_NOT_SUPPORTED;
1556 if (cParms >= 1)
1557 {
1558 ASSERT_GUEST_RETURN(paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE);
1559 rcSkip = (int32_t)paParms[0].u.uint32;
1560 }
1561
1562 uint32_t idMsg = UINT32_MAX;
1563 if (cParms >= 2)
1564 {
1565 ASSERT_GUEST_RETURN(paParms[1].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE);
1566 idMsg = paParms[1].u.uint32;
1567 }
1568
1569 /*
1570 * Do the job.
1571 */
1572 HostMsg *pFirstMsg = RTListGetFirstCpp(&pClient->m_HostMsgList, HostMsg, m_ListEntry);
1573 if (pFirstMsg)
1574 {
1575 if ( pFirstMsg->mType == idMsg
1576 || idMsg == UINT32_MAX)
1577 {
1578 int rc = mpHelpers->pfnCallComplete(hCall, VINF_SUCCESS);
1579 if (RT_SUCCESS(rc))
1580 {
1581 /*
1582 * Remove the message from the queue.
1583 */
1584 Assert(RTListNodeIsFirst(&pClient->m_HostMsgList, &pFirstMsg->m_ListEntry) );
1585 RTListNodeRemove(&pFirstMsg->m_ListEntry);
1586
1587 /*
1588 * Compose a reply to the host service.
1589 */
1590 VBOXHGCMSVCPARM aReplyParams[5];
1591 HGCMSvcSetU32(&aReplyParams[0], pFirstMsg->m_idContext);
1592 switch (pFirstMsg->mType)
1593 {
1594 case HOST_MSG_EXEC_CMD:
1595 HGCMSvcSetU32(&aReplyParams[1], 0); /* pid */
1596 HGCMSvcSetU32(&aReplyParams[2], PROC_STS_ERROR); /* status */
1597 HGCMSvcSetU32(&aReplyParams[3], rcSkip); /* flags / whatever */
1598 HGCMSvcSetPv(&aReplyParams[4], NULL, 0); /* data buffer */
1599 hostCallback(GUEST_MSG_EXEC_STATUS, 5, aReplyParams);
1600 break;
1601
1602 case HOST_MSG_SESSION_CREATE:
1603 HGCMSvcSetU32(&aReplyParams[1], GUEST_SESSION_NOTIFYTYPE_ERROR); /* type */
1604 HGCMSvcSetU32(&aReplyParams[2], rcSkip); /* result */
1605 hostCallback(GUEST_MSG_SESSION_NOTIFY, 3, aReplyParams);
1606 break;
1607
1608 case HOST_MSG_EXEC_SET_INPUT:
1609 HGCMSvcSetU32(&aReplyParams[1], pFirstMsg->mParmCount >= 2 ? pFirstMsg->mpParms[1].u.uint32 : 0);
1610 HGCMSvcSetU32(&aReplyParams[2], INPUT_STS_ERROR); /* status */
1611 HGCMSvcSetU32(&aReplyParams[3], rcSkip); /* flags / whatever */
1612 HGCMSvcSetU32(&aReplyParams[4], 0); /* bytes consumed */
1613 hostCallback(GUEST_MSG_EXEC_INPUT_STATUS, 5, aReplyParams);
1614 break;
1615
1616 case HOST_MSG_FILE_OPEN:
1617 HGCMSvcSetU32(&aReplyParams[1], GUEST_FILE_NOTIFYTYPE_OPEN); /* type*/
1618 HGCMSvcSetU32(&aReplyParams[2], rcSkip); /* rc */
1619 HGCMSvcSetU32(&aReplyParams[3], VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pFirstMsg->m_idContext)); /* handle */
1620 hostCallback(GUEST_MSG_FILE_NOTIFY, 4, aReplyParams);
1621 break;
1622 case HOST_MSG_FILE_CLOSE:
1623 HGCMSvcSetU32(&aReplyParams[1], GUEST_FILE_NOTIFYTYPE_ERROR); /* type*/
1624 HGCMSvcSetU32(&aReplyParams[2], rcSkip); /* rc */
1625 hostCallback(GUEST_MSG_FILE_NOTIFY, 3, aReplyParams);
1626 break;
1627 case HOST_MSG_FILE_READ:
1628 case HOST_MSG_FILE_READ_AT:
1629 HGCMSvcSetU32(&aReplyParams[1], GUEST_FILE_NOTIFYTYPE_READ); /* type */
1630 HGCMSvcSetU32(&aReplyParams[2], rcSkip); /* rc */
1631 HGCMSvcSetPv(&aReplyParams[3], NULL, 0); /* data buffer */
1632 hostCallback(GUEST_MSG_FILE_NOTIFY, 4, aReplyParams);
1633 break;
1634 case HOST_MSG_FILE_WRITE:
1635 case HOST_MSG_FILE_WRITE_AT:
1636 HGCMSvcSetU32(&aReplyParams[1], GUEST_FILE_NOTIFYTYPE_WRITE); /* type */
1637 HGCMSvcSetU32(&aReplyParams[2], rcSkip); /* rc */
1638 HGCMSvcSetU32(&aReplyParams[3], 0); /* bytes written */
1639 hostCallback(GUEST_MSG_FILE_NOTIFY, 4, aReplyParams);
1640 break;
1641 case HOST_MSG_FILE_SEEK:
1642 HGCMSvcSetU32(&aReplyParams[1], GUEST_FILE_NOTIFYTYPE_SEEK); /* type */
1643 HGCMSvcSetU32(&aReplyParams[2], rcSkip); /* rc */
1644 HGCMSvcSetU64(&aReplyParams[3], 0); /* actual */
1645 hostCallback(GUEST_MSG_FILE_NOTIFY, 4, aReplyParams);
1646 break;
1647 case HOST_MSG_FILE_TELL:
1648 HGCMSvcSetU32(&aReplyParams[1], GUEST_FILE_NOTIFYTYPE_TELL); /* type */
1649 HGCMSvcSetU32(&aReplyParams[2], rcSkip); /* rc */
1650 HGCMSvcSetU64(&aReplyParams[3], 0); /* actual */
1651 hostCallback(GUEST_MSG_FILE_NOTIFY, 4, aReplyParams);
1652 break;
1653 case HOST_MSG_FILE_SET_SIZE:
1654 HGCMSvcSetU32(&aReplyParams[1], GUEST_FILE_NOTIFYTYPE_SET_SIZE); /* type */
1655 HGCMSvcSetU32(&aReplyParams[2], rcSkip); /* rc */
1656 HGCMSvcSetU64(&aReplyParams[3], 0); /* actual */
1657 hostCallback(GUEST_MSG_FILE_NOTIFY, 4, aReplyParams);
1658 break;
1659
1660 case HOST_MSG_EXEC_GET_OUTPUT: /** @todo This can't be right/work. */
1661 case HOST_MSG_EXEC_TERMINATE: /** @todo This can't be right/work. */
1662 case HOST_MSG_EXEC_WAIT_FOR: /** @todo This can't be right/work. */
1663 case HOST_MSG_PATH_USER_DOCUMENTS:
1664 case HOST_MSG_PATH_USER_HOME:
1665 case HOST_MSG_PATH_RENAME:
1666 case HOST_MSG_DIR_REMOVE:
1667 default:
1668 HGCMSvcSetU32(&aReplyParams[1], pFirstMsg->mType);
1669 HGCMSvcSetU32(&aReplyParams[2], (uint32_t)rcSkip);
1670 HGCMSvcSetPv(&aReplyParams[3], NULL, 0);
1671 hostCallback(GUEST_MSG_REPLY, 4, aReplyParams);
1672 break;
1673 }
1674
1675 /*
1676 * Free the message.
1677 */
1678 pFirstMsg->Delete();
1679 }
1680 else
1681 LogFunc(("pfnCallComplete -> %Rrc\n", rc));
1682 return VINF_HGCM_ASYNC_EXECUTE; /* The caller must not complete it. */
1683 }
1684 LogFunc(("Warning: GUEST_MSG_SKIP mismatch! Found %u, caller expected %u!\n", pFirstMsg->mType, idMsg));
1685 return VERR_MISMATCH;
1686 }
1687 return VERR_NOT_FOUND;
1688}
1689
1690
1691/**
1692 * Implements GUEST_SESSION_PREPARE.
1693 *
1694 * @returns VBox status code.
1695 * @retval VINF_HGCM_ASYNC_EXECUTE on success as we complete the message.
1696 * @retval VERR_OUT_OF_RESOURCES if too many pending sessions hanging around.
1697 * @retval VERR_OUT_OF_RANGE if the session ID outside the allowed range.
1698 * @retval VERR_BUFFER_OVERFLOW if key too large.
1699 * @retval VERR_BUFFER_UNDERFLOW if key too small.
1700 * @retval VERR_ACCESS_DENIED if not master or in legacy mode.
1701 * @retval VERR_DUPLICATE if the session ID has been prepared already.
1702 *
1703 * @param pClient The client state.
1704 * @param hCall The call handle for completing it.
1705 * @param cParms Number of parameters.
1706 * @param paParms The parameters.
1707 */
1708int GstCtrlService::clientSessionPrepare(ClientState *pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1709{
1710 /*
1711 * Validate parameters.
1712 */
1713 ASSERT_GUEST_RETURN(cParms == 2, VERR_WRONG_PARAMETER_COUNT);
1714 ASSERT_GUEST_RETURN(paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE);
1715 uint32_t const idSession = paParms[0].u.uint32;
1716 ASSERT_GUEST_RETURN(idSession >= 1, VERR_OUT_OF_RANGE);
1717 ASSERT_GUEST_RETURN(idSession <= 0xfff0, VERR_OUT_OF_RANGE);
1718
1719 ASSERT_GUEST_RETURN(paParms[1].type == VBOX_HGCM_SVC_PARM_PTR, VERR_WRONG_PARAMETER_TYPE);
1720 uint32_t const cbKey = paParms[1].u.pointer.size;
1721 void const *pvKey = paParms[1].u.pointer.addr;
1722 ASSERT_GUEST_RETURN(cbKey >= 64, VERR_BUFFER_UNDERFLOW);
1723 ASSERT_GUEST_RETURN(cbKey <= _16K, VERR_BUFFER_OVERFLOW);
1724
1725 ASSERT_GUEST_RETURN(pClient->m_fIsMaster, VERR_ACCESS_DENIED);
1726 ASSERT_GUEST_RETURN(!m_fLegacyMode, VERR_ACCESS_DENIED);
1727 Assert(m_idMasterClient == pClient->m_idClient);
1728 Assert(m_pMasterClient == pClient);
1729
1730 /* Now that we know it's the master, we can check for session ID duplicates. */
1731 GstCtrlPreparedSession *pCur;
1732 RTListForEach(&m_PreparedSessions, pCur, GstCtrlPreparedSession, ListEntry)
1733 {
1734 ASSERT_GUEST_RETURN(pCur->idSession != idSession, VERR_DUPLICATE);
1735 }
1736
1737 /*
1738 * Make a copy of the session ID and key.
1739 */
1740 ASSERT_GUEST_RETURN(m_cPreparedSessions < 128, VERR_OUT_OF_RESOURCES);
1741
1742 GstCtrlPreparedSession *pPrepped = (GstCtrlPreparedSession *)RTMemAlloc(RT_UOFFSETOF_DYN(GstCtrlPreparedSession, abKey[cbKey]));
1743 AssertReturn(pPrepped, VERR_NO_MEMORY);
1744 pPrepped->idSession = idSession;
1745 pPrepped->cbKey = cbKey;
1746 memcpy(pPrepped->abKey, pvKey, cbKey);
1747
1748 RTListAppend(&m_PreparedSessions, &pPrepped->ListEntry);
1749 m_cPreparedSessions++;
1750
1751 /*
1752 * Try complete the message.
1753 */
1754 int rc = mpHelpers->pfnCallComplete(hCall, VINF_SUCCESS);
1755 if (RT_SUCCESS(rc))
1756 LogFlow(("Prepared %u with a %#x byte key (%u pending).\n", idSession, cbKey, m_cPreparedSessions));
1757 else
1758 {
1759 LogFunc(("pfnCallComplete -> %Rrc\n", rc));
1760 RTListNodeRemove(&pPrepped->ListEntry);
1761 RTMemFree(pPrepped);
1762 m_cPreparedSessions--;
1763 }
1764 return VINF_HGCM_ASYNC_EXECUTE; /* The caller must not complete it. */
1765}
1766
1767
1768/**
1769 * Implements GUEST_SESSION_CANCEL_PREPARED.
1770 *
1771 * @returns VBox status code.
1772 * @retval VINF_HGCM_ASYNC_EXECUTE on success as we complete the message.
1773 * @retval VWRN_NOT_FOUND if no session with the specified ID.
1774 * @retval VERR_ACCESS_DENIED if not master or in legacy mode.
1775 *
1776 * @param pClient The client state.
1777 * @param cParms Number of parameters.
1778 * @param paParms The parameters.
1779 */
1780int GstCtrlService::clientSessionCancelPrepared(ClientState *pClient, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1781{
1782 /*
1783 * Validate parameters.
1784 */
1785 ASSERT_GUEST_RETURN(cParms == 1, VERR_WRONG_PARAMETER_COUNT);
1786 ASSERT_GUEST_RETURN(paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE);
1787 uint32_t const idSession = paParms[0].u.uint32;
1788
1789 ASSERT_GUEST_RETURN(pClient->m_fIsMaster, VERR_ACCESS_DENIED);
1790 ASSERT_GUEST_RETURN(!m_fLegacyMode, VERR_ACCESS_DENIED);
1791 Assert(m_idMasterClient == pClient->m_idClient);
1792 Assert(m_pMasterClient == pClient);
1793
1794 /*
1795 * Do the work.
1796 */
1797 int rc = VWRN_NOT_FOUND;
1798 if (idSession == UINT32_MAX)
1799 {
1800 GstCtrlPreparedSession *pCur, *pNext;
1801 RTListForEachSafe(&m_PreparedSessions, pCur, pNext, GstCtrlPreparedSession, ListEntry)
1802 {
1803 RTListNodeRemove(&pCur->ListEntry);
1804 RTMemFree(pCur);
1805 rc = VINF_SUCCESS;
1806 }
1807 m_cPreparedSessions = 0;
1808 }
1809 else
1810 {
1811 GstCtrlPreparedSession *pCur, *pNext;
1812 RTListForEachSafe(&m_PreparedSessions, pCur, pNext, GstCtrlPreparedSession, ListEntry)
1813 {
1814 if (pCur->idSession == idSession)
1815 {
1816 RTListNodeRemove(&pCur->ListEntry);
1817 RTMemFree(pCur);
1818 m_cPreparedSessions -= 1;
1819 rc = VINF_SUCCESS;
1820 break;
1821 }
1822 }
1823 }
1824 return VINF_SUCCESS;
1825}
1826
1827
1828/**
1829 * Implements GUEST_SESSION_ACCEPT.
1830 *
1831 * @returns VBox status code.
1832 * @retval VINF_HGCM_ASYNC_EXECUTE on success as we complete the message.
1833 * @retval VERR_NOT_FOUND if the specified session ID wasn't found.
1834 * @retval VERR_MISMATCH if the key didn't match.
1835 * @retval VERR_ACCESS_DENIED if we're in legacy mode or is master.
1836 * @retval VERR_RESOURCE_BUSY if the client is already associated with a
1837 * session.
1838 *
1839 * @param pClient The client state.
1840 * @param hCall The call handle for completing it.
1841 * @param cParms Number of parameters.
1842 * @param paParms The parameters.
1843 */
1844int GstCtrlService::clientSessionAccept(ClientState *pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1845{
1846 /*
1847 * Validate parameters.
1848 */
1849 ASSERT_GUEST_RETURN(cParms == 2, VERR_WRONG_PARAMETER_COUNT);
1850 ASSERT_GUEST_RETURN(paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE);
1851 uint32_t const idSession = paParms[0].u.uint32;
1852 ASSERT_GUEST_RETURN(idSession >= 1, VERR_OUT_OF_RANGE);
1853 ASSERT_GUEST_RETURN(idSession <= 0xfff0, VERR_OUT_OF_RANGE);
1854
1855 ASSERT_GUEST_RETURN(paParms[1].type == VBOX_HGCM_SVC_PARM_PTR, VERR_WRONG_PARAMETER_TYPE);
1856 uint32_t const cbKey = paParms[1].u.pointer.size;
1857 void const *pvKey = paParms[1].u.pointer.addr;
1858 ASSERT_GUEST_RETURN(cbKey >= 64, VERR_BUFFER_UNDERFLOW);
1859 ASSERT_GUEST_RETURN(cbKey <= _16K, VERR_BUFFER_OVERFLOW);
1860
1861 ASSERT_GUEST_RETURN(!pClient->m_fIsMaster, VERR_ACCESS_DENIED);
1862 ASSERT_GUEST_RETURN(!m_fLegacyMode, VERR_ACCESS_DENIED);
1863 Assert(m_idMasterClient != pClient->m_idClient);
1864 Assert(m_pMasterClient != pClient);
1865 ASSERT_GUEST_RETURN(pClient->m_idSession == UINT32_MAX, VERR_RESOURCE_BUSY);
1866
1867 /*
1868 * Look for the specified session and match the key to it.
1869 */
1870 GstCtrlPreparedSession *pCur;
1871 RTListForEach(&m_PreparedSessions, pCur, GstCtrlPreparedSession, ListEntry)
1872 {
1873 if (pCur->idSession == idSession)
1874 {
1875 if ( pCur->cbKey == cbKey
1876 && memcmp(pCur->abKey, pvKey, cbKey) == 0)
1877 {
1878 /*
1879 * We've got a match.
1880 * Try insert it into the sessio ID map and complete the request.
1881 */
1882 try
1883 {
1884 m_SessionIdMap[idSession] = pClient;
1885 }
1886 catch (std::bad_alloc &)
1887 {
1888 LogFunc(("Out of memory!\n"));
1889 return VERR_NO_MEMORY;
1890 }
1891
1892 int rc = mpHelpers->pfnCallComplete(hCall, VINF_SUCCESS);
1893 if (RT_SUCCESS(rc))
1894 {
1895 pClient->m_idSession = idSession;
1896
1897 RTListNodeRemove(&pCur->ListEntry);
1898 RTMemFree(pCur);
1899 m_cPreparedSessions -= 1;
1900 Log(("[Client %RU32] accepted session id %u.\n", pClient->m_idClient, idSession));
1901 }
1902 else
1903 {
1904 LogFunc(("pfnCallComplete -> %Rrc\n", rc));
1905 m_SessionIdMap.erase(idSession);
1906 }
1907 return VINF_HGCM_ASYNC_EXECUTE; /* The caller must not complete it. */
1908 }
1909 LogFunc(("Key mismatch for %u!\n", pClient->m_idClient));
1910 return VERR_MISMATCH;
1911 }
1912 }
1913
1914 LogFunc(("No client prepared for %u!\n", pClient->m_idClient));
1915 return VERR_NOT_FOUND;
1916}
1917
1918
1919/**
1920 * Client asks another client (guest) session to close.
1921 *
1922 * @returns VBox status code.
1923 * @param pClient The client state.
1924 * @param cParms Number of parameters.
1925 * @param paParms Array of parameters.
1926 */
1927int GstCtrlService::clientSessionCloseOther(ClientState *pClient, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1928{
1929 /*
1930 * Validate input.
1931 */
1932 ASSERT_GUEST_RETURN(cParms == 2, VERR_WRONG_PARAMETER_COUNT);
1933 ASSERT_GUEST_RETURN(paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE);
1934 uint32_t const idContext = paParms[0].u.uint32;
1935
1936 ASSERT_GUEST_RETURN(paParms[1].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE);
1937 uint32_t const fFlags = paParms[1].u.uint32;
1938
1939 ASSERT_GUEST_RETURN(pClient->m_fIsMaster || (m_fLegacyMode && pClient->m_idSession == UINT32_MAX), VERR_ACCESS_DENIED);
1940
1941 /*
1942 * Forward the message to the destiation.
1943 * Since we modify the first parameter, we must make a copy of the parameters.
1944 */
1945 VBOXHGCMSVCPARM aParms[2];
1946 HGCMSvcSetU64(&aParms[0], idContext | VBOX_GUESTCTRL_DST_SESSION);
1947 HGCMSvcSetU32(&aParms[1], fFlags);
1948 int rc = hostProcessMessage(HOST_MSG_SESSION_CLOSE, RT_ELEMENTS(aParms), aParms);
1949
1950 LogFlowFunc(("Closing guest context ID=%RU32 (from client ID=%RU32) returned with rc=%Rrc\n", idContext, pClient->m_idClient, rc));
1951 return rc;
1952}
1953
1954
1955/**
1956 * For compatiblity with old additions only - filtering / set session ID.
1957 *
1958 * @return VBox status code.
1959 * @param pClient The client state.
1960 * @param cParms Number of parameters.
1961 * @param paParms Array of parameters.
1962 */
1963int GstCtrlService::clientMsgOldFilterSet(ClientState *pClient, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1964{
1965 /*
1966 * Validate input and access.
1967 */
1968 ASSERT_GUEST_RETURN(cParms == 4, VERR_WRONG_PARAMETER_COUNT);
1969 ASSERT_GUEST_RETURN(paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE);
1970 uint32_t uValue = paParms[0].u.uint32;
1971 ASSERT_GUEST_RETURN(paParms[1].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE);
1972 uint32_t fMaskAdd = paParms[1].u.uint32;
1973 ASSERT_GUEST_RETURN(paParms[2].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE);
1974 uint32_t fMaskRemove = paParms[2].u.uint32;
1975 ASSERT_GUEST_RETURN(paParms[3].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE); /* flags, unused */
1976
1977 /*
1978 * We have a bunch of expectations here:
1979 * - Never called in non-legacy mode.
1980 * - Only called once per session.
1981 * - Never called by the master session.
1982 * - Clients that doesn't wish for any messages passes all zeros.
1983 * - All other calls has a unique session ID.
1984 */
1985 ASSERT_GUEST_LOGREL_RETURN(m_fLegacyMode, VERR_WRONG_ORDER);
1986 ASSERT_GUEST_LOGREL_MSG_RETURN(pClient->m_idSession == UINT32_MAX, ("m_idSession=%#x\n", pClient->m_idSession),
1987 VERR_WRONG_ORDER);
1988 ASSERT_GUEST_LOGREL_RETURN(!pClient->m_fIsMaster, VERR_WRONG_ORDER);
1989
1990 if (uValue == 0)
1991 {
1992 ASSERT_GUEST_LOGREL(fMaskAdd == 0);
1993 ASSERT_GUEST_LOGREL(fMaskRemove == 0);
1994 /* Nothing to do, already muted (UINT32_MAX). */
1995 }
1996 else
1997 {
1998 ASSERT_GUEST_LOGREL(fMaskAdd == UINT32_C(0xf8000000));
1999 ASSERT_GUEST_LOGREL(fMaskRemove == 0);
2000
2001 uint32_t idSession = VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(uValue);
2002 ASSERT_GUEST_LOGREL_MSG_RETURN(idSession > 0, ("idSession=%u (%#x)\n", idSession, uValue), VERR_OUT_OF_RANGE);
2003
2004 ClientStateMap::iterator ItConflict = m_SessionIdMap.find(idSession);
2005 ASSERT_GUEST_LOGREL_MSG_RETURN(ItConflict == m_SessionIdMap.end(),
2006 ("idSession=%u uValue=%#x idClient=%u; conflicting with client %u\n",
2007 idSession, uValue, pClient->m_idClient, ItConflict->second->m_idClient),
2008 VERR_DUPLICATE);
2009
2010 /* Commit it. */
2011 try
2012 {
2013 m_SessionIdMap[idSession] = pClient;
2014 }
2015 catch (std::bad_alloc &)
2016 {
2017 LogFunc(("Out of memory\n"));
2018 return VERR_NO_MEMORY;
2019 }
2020 pClient->m_idSession = idSession;
2021 }
2022 return VINF_SUCCESS;
2023}
2024
2025
2026/**
2027 * For compatibility with old additions only - skip the current message w/o
2028 * calling main code.
2029 *
2030 * Please note that we don't care if the caller cancelled the request, because
2031 * old additions code didn't give damn about VERR_INTERRUPT.
2032 *
2033 * @return VBox status code.
2034 * @param pClient The client state.
2035 * @param hCall The call handle for completing it.
2036 * @param cParms Number of parameters.
2037 */
2038int GstCtrlService::clientMsgOldSkip(ClientState *pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms)
2039{
2040 /*
2041 * Validate input and access.
2042 */
2043 ASSERT_GUEST_RETURN(cParms == 1, VERR_WRONG_PARAMETER_COUNT);
2044
2045 /*
2046 * Execute the request.
2047 *
2048 * Note! As it turns out the old and new skip should be mostly the same. The
2049 * pre-6.0 GAs (up to BETA3) has a hack which tries to issue a
2050 * VERR_NOT_SUPPORTED reply to unknown host requests, however the 5.2.x
2051 * and earlier GAs doesn't. We need old skip behavior only for the 6.0
2052 * beta GAs, nothing else.
2053 * So, we have to track whether they issued a MSG_REPLY or not. Wonderful.
2054 */
2055 HostMsg *pFirstMsg = RTListGetFirstCpp(&pClient->m_HostMsgList, HostMsg, m_ListEntry);
2056 if (pFirstMsg)
2057 {
2058 uint32_t const idMsg = pFirstMsg->mType;
2059 bool const f60BetaHackInPlay = pFirstMsg->m_f60BetaHackInPlay;
2060 int rc;
2061 if (!f60BetaHackInPlay)
2062 rc = clientMsgSkip(pClient, hCall, 0, NULL);
2063 else
2064 {
2065 RTListNodeRemove(&pFirstMsg->m_ListEntry);
2066 pFirstMsg->Delete();
2067 rc = VINF_SUCCESS;
2068 }
2069
2070 /* Reset legacy message wait/get state: */
2071 if (RT_SUCCESS(rc))
2072 {
2073 pClient->mHostMsgRc = VINF_SUCCESS;
2074 pClient->mHostMsgTries = 0;
2075 pClient->mPeekCount = 0;
2076 }
2077
2078 LogFlowFunc(("[Client %RU32] Legacy message skipping: Skipped %u (%s)%s!\n",
2079 pClient->m_idClient, idMsg, GstCtrlHostMsgtoStr((eHostMsg)idMsg), f60BetaHackInPlay ? " hack style" : ""));
2080 NOREF(idMsg);
2081 return rc;
2082 }
2083 LogFlowFunc(("[Client %RU32] Legacy message skipping: No messages pending!\n", pClient->m_idClient));
2084 return VINF_SUCCESS;
2085}
2086
2087
2088/**
2089 * Forwards client call to the Main API.
2090 *
2091 * This is typically notifications and replys.
2092 *
2093 * @returns VBox status code.
2094 * @param pClient The client state.
2095 * @param idMsg Message ID that occured.
2096 * @param cParms Number of parameters.
2097 * @param paParms Array of parameters.
2098 */
2099int GstCtrlService::clientToMain(ClientState *pClient, uint32_t idMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
2100{
2101 /*
2102 * Do input validation. This class of messages all have a 32-bit context ID as
2103 * the first parameter, so make sure it is there and appropriate for the caller.
2104 */
2105 ASSERT_GUEST_RETURN(cParms >= 1, VERR_WRONG_PARAMETER_COUNT);
2106 ASSERT_GUEST_RETURN(paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_COUNT);
2107 uint32_t const idContext = paParms[0].u.uint32;
2108 uint32_t const idSession = VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(idContext);
2109
2110 ASSERT_GUEST_MSG_RETURN( pClient->m_idSession == idSession
2111 || pClient->m_fIsMaster
2112 || ( m_fLegacyMode /* (see bugref:9313#c16) */
2113 && pClient->m_idSession == UINT32_MAX
2114 && ( idMsg == GUEST_MSG_EXEC_STATUS
2115 || idMsg == GUEST_MSG_SESSION_NOTIFY)),
2116 ("idSession=%u (CID=%#x) m_idSession=%u idClient=%u idMsg=%u (%s)\n", idSession, idContext,
2117 pClient->m_idSession, pClient->m_idClient, idMsg, GstCtrlGuestMsgToStr((eGuestMsg)idMsg)),
2118 VERR_ACCESS_DENIED);
2119
2120 /*
2121 * It seems okay, so make the call.
2122 */
2123 return hostCallback(idMsg, cParms, paParms);
2124}
2125
2126
2127/**
2128 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnCall}
2129 *
2130 * @note All functions which do not involve an unreasonable delay will be
2131 * handled synchronously. If needed, we will add a request handler
2132 * thread in future for those which do.
2133 * @thread HGCM
2134 */
2135/*static*/ DECLCALLBACK(void)
2136GstCtrlService::svcCall(void *pvService, VBOXHGCMCALLHANDLE hCall, uint32_t idClient, void *pvClient,
2137 uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[], uint64_t tsArrival)
2138{
2139 LogFlowFunc(("[Client %RU32] u32Function=%RU32 (%s), cParms=%RU32, paParms=0x%p\n",
2140 idClient, u32Function, GstCtrlGuestMsgToStr((eGuestMsg)u32Function), cParms, paParms));
2141 RT_NOREF(tsArrival, idClient);
2142
2143 /*
2144 * Convert opaque pointers to typed ones.
2145 */
2146 SELF *pThis = reinterpret_cast<SELF *>(pvService);
2147 AssertPtrReturnVoid(pThis);
2148 ClientState *pClient = reinterpret_cast<ClientState *>(pvClient);
2149 AssertReturnVoidStmt(pClient, pThis->mpHelpers->pfnCallComplete(hCall, VERR_INVALID_CLIENT_ID));
2150 Assert(pClient->m_idClient == idClient);
2151
2152 /*
2153 * Do the dispatching.
2154 */
2155 int rc;
2156 switch (u32Function)
2157 {
2158 case GUEST_MSG_MAKE_ME_MASTER:
2159 LogFlowFunc(("[Client %RU32] GUEST_MAKE_ME_MASTER\n", idClient));
2160 rc = pThis->clientMakeMeMaster(pClient, hCall, cParms);
2161 break;
2162 case GUEST_MSG_REPORT_FEATURES:
2163 LogFlowFunc(("[Client %RU32] GUEST_MSG_REPORT_FEATURES\n", idClient));
2164 rc = pThis->clientReportFeatures(pClient, hCall, cParms, paParms);
2165 break;
2166 case GUEST_MSG_QUERY_FEATURES:
2167 LogFlowFunc(("[Client %RU32] GUEST_MSG_QUERY_FEATURES\n", idClient));
2168 rc = pThis->clientQueryFeatures(pClient, hCall, cParms, paParms);
2169 break;
2170 case GUEST_MSG_PEEK_NOWAIT:
2171 LogFlowFunc(("[Client %RU32] GUEST_MSG_PEEK_NOWAIT\n", idClient));
2172 rc = pThis->clientMsgPeek(pClient, hCall, cParms, paParms, false /*fWait*/);
2173 break;
2174 case GUEST_MSG_PEEK_WAIT:
2175 LogFlowFunc(("[Client %RU32] GUEST_MSG_PEEK_WAIT\n", idClient));
2176 rc = pThis->clientMsgPeek(pClient, hCall, cParms, paParms, true /*fWait*/);
2177 break;
2178 case GUEST_MSG_GET:
2179 LogFlowFunc(("[Client %RU32] GUEST_MSG_GET\n", idClient));
2180 rc = pThis->clientMsgGet(pClient, hCall, cParms, paParms);
2181 break;
2182 case GUEST_MSG_CANCEL:
2183 LogFlowFunc(("[Client %RU32] GUEST_MSG_CANCEL\n", idClient));
2184 rc = pThis->clientMsgCancel(pClient, cParms);
2185 break;
2186 case GUEST_MSG_SKIP:
2187 LogFlowFunc(("[Client %RU32] GUEST_MSG_SKIP\n", idClient));
2188 rc = pThis->clientMsgSkip(pClient, hCall, cParms, paParms);
2189 break;
2190 case GUEST_MSG_SESSION_PREPARE:
2191 LogFlowFunc(("[Client %RU32] GUEST_SESSION_PREPARE\n", idClient));
2192 rc = pThis->clientSessionPrepare(pClient, hCall, cParms, paParms);
2193 break;
2194 case GUEST_MSG_SESSION_CANCEL_PREPARED:
2195 LogFlowFunc(("[Client %RU32] GUEST_SESSION_CANCEL_PREPARED\n", idClient));
2196 rc = pThis->clientSessionCancelPrepared(pClient, cParms, paParms);
2197 break;
2198 case GUEST_MSG_SESSION_ACCEPT:
2199 LogFlowFunc(("[Client %RU32] GUEST_SESSION_ACCEPT\n", idClient));
2200 rc = pThis->clientSessionAccept(pClient, hCall, cParms, paParms);
2201 break;
2202 case GUEST_MSG_SESSION_CLOSE:
2203 LogFlowFunc(("[Client %RU32] GUEST_SESSION_CLOSE\n", idClient));
2204 rc = pThis->clientSessionCloseOther(pClient, cParms, paParms);
2205 break;
2206
2207 /*
2208 * Stuff the goes to various main objects:
2209 */
2210 case GUEST_MSG_REPLY:
2211 if (cParms >= 3 && paParms[2].u.uint32 == (uint32_t)VERR_NOT_SUPPORTED)
2212 {
2213 HostMsg *pFirstMsg = RTListGetFirstCpp(&pClient->m_HostMsgList, HostMsg, m_ListEntry);
2214 if (pFirstMsg && pFirstMsg->m_idContext == paParms[0].u.uint32)
2215 pFirstMsg->m_f60BetaHackInPlay = true;
2216 }
2217 RT_FALL_THROUGH();
2218 case GUEST_MSG_PROGRESS_UPDATE:
2219 case GUEST_MSG_SESSION_NOTIFY:
2220 case GUEST_MSG_EXEC_OUTPUT:
2221 case GUEST_MSG_EXEC_STATUS:
2222 case GUEST_MSG_EXEC_INPUT_STATUS:
2223 case GUEST_MSG_EXEC_IO_NOTIFY:
2224 case GUEST_MSG_DIR_NOTIFY:
2225 case GUEST_MSG_FILE_NOTIFY:
2226 LogFlowFunc(("[Client %RU32] %s\n", idClient, GstCtrlGuestMsgToStr((eGuestMsg)u32Function)));
2227 rc = pThis->clientToMain(pClient, u32Function /* Msg */, cParms, paParms);
2228 Assert(rc != VINF_HGCM_ASYNC_EXECUTE);
2229 break;
2230
2231 /*
2232 * The remaining messages are here for compatibility with older Guest Additions:
2233 */
2234 case GUEST_MSG_WAIT:
2235 LogFlowFunc(("[Client %RU32] GUEST_MSG_WAIT\n", idClient));
2236 pThis->clientMsgOldGet(pClient, hCall, cParms, paParms);
2237 rc = VINF_HGCM_ASYNC_EXECUTE;
2238 break;
2239
2240 case GUEST_MSG_SKIP_OLD:
2241 LogFlowFunc(("[Client %RU32] GUEST_MSG_SKIP_OLD\n", idClient));
2242 rc = pThis->clientMsgOldSkip(pClient, hCall, cParms);
2243 break;
2244
2245 case GUEST_MSG_FILTER_SET:
2246 LogFlowFunc(("[Client %RU32] GUEST_MSG_FILTER_SET\n", idClient));
2247 rc = pThis->clientMsgOldFilterSet(pClient, cParms, paParms);
2248 break;
2249
2250 case GUEST_MSG_FILTER_UNSET:
2251 LogFlowFunc(("[Client %RU32] GUEST_MSG_FILTER_UNSET\n", idClient));
2252 rc = VERR_NOT_IMPLEMENTED;
2253 break;
2254
2255 /*
2256 * Anything else shall return invalid function.
2257 * Note! We used to return VINF_SUCCESS for these. See bugref:9313
2258 * and Guest::i_notifyCtrlDispatcher().
2259 */
2260 default:
2261 ASSERT_GUEST_MSG_FAILED(("u32Function=%RU32 (%#x)\n", u32Function, u32Function));
2262 rc = VERR_INVALID_FUNCTION;
2263 break;
2264 }
2265
2266 if (rc != VINF_HGCM_ASYNC_EXECUTE)
2267 {
2268 /* Tell the client that the call is complete (unblocks waiting). */
2269 LogFlowFunc(("[Client %RU32] Calling pfnCallComplete w/ rc=%Rrc\n", idClient, rc));
2270 AssertPtr(pThis->mpHelpers);
2271 pThis->mpHelpers->pfnCallComplete(hCall, rc);
2272 }
2273}
2274
2275
2276/**
2277 * Notifies the host (using low-level HGCM callbacks) about an event
2278 * which was sent from the client.
2279 *
2280 * @returns VBox status code.
2281 * @param u32Function Message ID that occured.
2282 * @param cParms Number of parameters.
2283 * @param paParms Array of parameters.
2284 */
2285int GstCtrlService::hostCallback(uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
2286{
2287 LogFlowFunc(("u32Function=%RU32 (%s), cParms=%ld, paParms=%p\n",
2288 u32Function, GstCtrlGuestMsgToStr((eGuestMsg)u32Function), cParms, paParms));
2289
2290 int rc;
2291 if (mpfnHostCallback)
2292 {
2293 VBOXGUESTCTRLHOSTCALLBACK data = { cParms, paParms };
2294 rc = mpfnHostCallback(mpvHostData, u32Function, &data, sizeof(data));
2295 }
2296 else
2297 rc = VERR_NOT_SUPPORTED;
2298
2299 LogFlowFunc(("Returning rc=%Rrc\n", rc));
2300 return rc;
2301}
2302
2303
2304/**
2305 * Processes a message received from the host side and re-routes it to
2306 * a connect client on the guest.
2307 *
2308 * @returns VBox status code.
2309 * @param idMsg Message ID to process.
2310 * @param cParms Number of parameters.
2311 * @param paParms Array of parameters.
2312 */
2313int GstCtrlService::hostProcessMessage(uint32_t idMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
2314{
2315 /*
2316 * If no client is connected at all we don't buffer any host messages
2317 * and immediately return an error to the host. This avoids the host
2318 * waiting for a response from the guest side in case VBoxService on
2319 * the guest is not running/system is messed up somehow.
2320 */
2321 if (m_ClientStateMap.empty())
2322 {
2323 LogFlow(("GstCtrlService::hostProcessMessage: VERR_NOT_FOUND!\n"));
2324 return VERR_NOT_FOUND;
2325 }
2326
2327 /*
2328 * Create a host message for each destination.
2329 * Note! There is currently only one scenario in which we send a host
2330 * message to two recipients.
2331 */
2332 HostMsg *pHostMsg = new (std::nothrow) HostMsg();
2333 AssertReturn(pHostMsg, VERR_NO_MEMORY);
2334 int rc = pHostMsg->Init(idMsg, cParms, paParms);
2335 if (RT_SUCCESS(rc))
2336 {
2337 uint64_t const fDestinations = pHostMsg->m_idContextAndDst & VBOX_GUESTCTRL_DST_BOTH;
2338 HostMsg *pHostMsg2 = NULL;
2339 if (fDestinations != VBOX_GUESTCTRL_DST_BOTH)
2340 { /* likely */ }
2341 else
2342 {
2343 pHostMsg2 = new (std::nothrow) HostMsg();
2344 if (pHostMsg2)
2345 rc = pHostMsg2->Init(idMsg, cParms, paParms);
2346 else
2347 rc = VERR_NO_MEMORY;
2348 }
2349 if (RT_SUCCESS(rc))
2350 {
2351 LogFlowFunc(("Handling host message m_idContextAndDst=%#RX64, idMsg=%RU32, cParms=%RU32, paParms=%p, cClients=%zu\n",
2352 pHostMsg->m_idContextAndDst, idMsg, cParms, paParms, m_ClientStateMap.size()));
2353
2354 /*
2355 * Find the message destination and post it to the client. If the
2356 * session ID doesn't match any particular client it goes to the master.
2357 */
2358 AssertMsg(!m_ClientStateMap.empty(), ("Client state map is empty when it should not be!\n"));
2359
2360 /* Dispatch to the session. */
2361 if (fDestinations & VBOX_GUESTCTRL_DST_SESSION)
2362 {
2363 uint32_t const idSession = VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(pHostMsg->m_idContext);
2364 ClientStateMap::iterator It = m_SessionIdMap.find(idSession);
2365 if (It != m_SessionIdMap.end())
2366 {
2367 ClientState *pClient = It->second;
2368 Assert(pClient->m_idSession == idSession);
2369 RTListAppend(&pClient->m_HostMsgList, &pHostMsg->m_ListEntry);
2370 pHostMsg = pHostMsg2;
2371 pHostMsg2 = NULL;
2372
2373 int rc2 = pClient->Wakeup();
2374 LogFlowFunc(("Woke up client ID=%RU32 -> rc=%Rrc\n", pClient->m_idClient, rc2));
2375 RT_NOREF(rc2);
2376 rc = VINF_SUCCESS;
2377 }
2378 else
2379 {
2380 LogFunc(("No client with session ID %u was found! (idMsg=%d %s)\n",
2381 idSession, idMsg, GstCtrlHostMsgtoStr((eHostMsg)idMsg)));
2382 rc = !(fDestinations & VBOX_GUESTCTRL_DST_ROOT_SVC) ? VERR_NOT_FOUND : VWRN_NOT_FOUND;
2383 }
2384 }
2385
2386 /* Does the message go to the root service? */
2387 if ( (fDestinations & VBOX_GUESTCTRL_DST_ROOT_SVC)
2388 && RT_SUCCESS(rc))
2389 {
2390 Assert(pHostMsg);
2391 if (m_pMasterClient)
2392 {
2393 RTListAppend(&m_pMasterClient->m_HostMsgList, &pHostMsg->m_ListEntry);
2394 pHostMsg = NULL;
2395
2396 int rc2 = m_pMasterClient->Wakeup();
2397 LogFlowFunc(("Woke up client ID=%RU32 (master) -> rc=%Rrc\n", m_pMasterClient->m_idClient, rc2));
2398 NOREF(rc2);
2399 }
2400 else
2401 rc = VERR_NOT_FOUND;
2402 }
2403 }
2404
2405 /* Drop unset messages. */
2406 if (pHostMsg2)
2407 pHostMsg2->Delete();
2408 }
2409 if (pHostMsg)
2410 pHostMsg->Delete();
2411
2412 if (RT_FAILURE(rc))
2413 LogFunc(("Failed %Rrc (idMsg=%u, cParms=%u)\n", rc, idMsg, cParms));
2414 return rc;
2415}
2416
2417
2418/**
2419 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnHostCall,
2420 * Wraps to the hostProcessMessage() member function.}
2421 */
2422/*static*/ DECLCALLBACK(int)
2423GstCtrlService::svcHostCall(void *pvService, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
2424{
2425 AssertLogRelReturn(RT_VALID_PTR(pvService), VERR_INVALID_PARAMETER);
2426 SELF *pThis = reinterpret_cast<SELF *>(pvService);
2427 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2428
2429 LogFlowFunc(("u32Function=%RU32, cParms=%RU32, paParms=0x%p\n", u32Function, cParms, paParms));
2430 AssertReturn(u32Function != HOST_MSG_CANCEL_PENDING_WAITS, VERR_INVALID_FUNCTION);
2431 return pThis->hostProcessMessage(u32Function, cParms, paParms);
2432}
2433
2434
2435
2436
2437/**
2438 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnSaveState}
2439 */
2440/*static*/ DECLCALLBACK(int)
2441GstCtrlService::svcSaveState(void *pvService, uint32_t idClient, void *pvClient, PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM)
2442{
2443 RT_NOREF(pvClient);
2444 SELF *pThis = reinterpret_cast<SELF *>(pvService);
2445 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2446
2447 /* Note! We don't need to save the idSession here because it's only used
2448 for sessions and the sessions are not persistent across a state
2449 save/restore. The Main objects aren't there. Clients shuts down.
2450 Only the root service survives, so remember who that is and its mode. */
2451
2452 pVMM->pfnSSMR3PutU32(pSSM, 1);
2453 pVMM->pfnSSMR3PutBool(pSSM, pThis->m_fLegacyMode);
2454 return pVMM->pfnSSMR3PutBool(pSSM, idClient == pThis->m_idMasterClient);
2455}
2456
2457
2458/**
2459 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnLoadState}
2460 */
2461/*static*/ DECLCALLBACK(int)
2462GstCtrlService::svcLoadState(void *pvService, uint32_t idClient, void *pvClient,
2463 PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, uint32_t uVersion)
2464{
2465 SELF *pThis = reinterpret_cast<SELF *>(pvService);
2466 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2467 ClientState *pClient = reinterpret_cast<ClientState *>(pvClient);
2468 AssertReturn(pClient, VERR_INVALID_CLIENT_ID);
2469 Assert(pClient->m_idClient == idClient);
2470
2471 if (uVersion >= HGCM_SAVED_STATE_VERSION)
2472 {
2473 uint32_t uSubVersion;
2474 int rc = pVMM->pfnSSMR3GetU32(pSSM, &uSubVersion);
2475 AssertRCReturn(rc, rc);
2476 if (uSubVersion != 1)
2477 return pVMM->pfnSSMR3SetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
2478 "sub version %u, expected 1\n", uSubVersion);
2479 bool fLegacyMode;
2480 rc = pVMM->pfnSSMR3GetBool(pSSM, &fLegacyMode);
2481 AssertRCReturn(rc, rc);
2482 pThis->m_fLegacyMode = fLegacyMode;
2483
2484 bool fIsMaster;
2485 rc = pVMM->pfnSSMR3GetBool(pSSM, &fIsMaster);
2486 AssertRCReturn(rc, rc);
2487
2488 pClient->m_fIsMaster = fIsMaster;
2489 if (fIsMaster)
2490 {
2491 pThis->m_pMasterClient = pClient;
2492 pThis->m_idMasterClient = idClient;
2493 }
2494 }
2495 else
2496 {
2497 /*
2498 * For old saved states we have to guess at who should be the master.
2499 * Given how HGCMService::CreateAndConnectClient and associates manage
2500 * and saves the client, the first client connecting will be restored
2501 * first. The only time this might go wrong if the there are zombie
2502 * VBoxService session processes in the restored guest, and I don't
2503 * we need to care too much about that scenario.
2504 *
2505 * Given how HGCM first re-connects the clients before this function
2506 * gets called, there isn't anything we need to do here it turns out. :-)
2507 */
2508 }
2509 pClient->m_fRestored = true;
2510 return VINF_SUCCESS;
2511}
2512
2513
2514/**
2515 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnRegisterExtension,
2516 * Installs a host callback for notifications of property changes.}
2517 */
2518/*static*/ DECLCALLBACK(int) GstCtrlService::svcRegisterExtension(void *pvService, PFNHGCMSVCEXT pfnExtension, void *pvExtension)
2519{
2520 SELF *pThis = reinterpret_cast<SELF *>(pvService);
2521 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2522 AssertPtrNullReturn(pfnExtension, VERR_INVALID_POINTER);
2523
2524 pThis->mpfnHostCallback = pfnExtension;
2525 pThis->mpvHostData = pvExtension;
2526 return VINF_SUCCESS;
2527}
2528
2529
2530/**
2531 * @copydoc FNVBOXHGCMSVCLOAD
2532 */
2533extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *pTable)
2534{
2535 int rc = VINF_SUCCESS;
2536
2537 LogFlowFunc(("pTable=%p\n", pTable));
2538
2539 if (!RT_VALID_PTR(pTable))
2540 rc = VERR_INVALID_PARAMETER;
2541 else
2542 {
2543 LogFlowFunc(("pTable->cbSize=%d, pTable->u32Version=0x%08X\n", pTable->cbSize, pTable->u32Version));
2544
2545 if ( pTable->cbSize != sizeof (VBOXHGCMSVCFNTABLE)
2546 || pTable->u32Version != VBOX_HGCM_SVC_VERSION)
2547 {
2548 rc = VERR_VERSION_MISMATCH;
2549 }
2550 else
2551 {
2552 GstCtrlService *pService = NULL;
2553 /* No exceptions may propagate outside. */
2554 try
2555 {
2556 pService = new GstCtrlService(pTable->pHelpers);
2557 }
2558 catch (int rcThrown)
2559 {
2560 rc = rcThrown;
2561 }
2562 catch(std::bad_alloc &)
2563 {
2564 rc = VERR_NO_MEMORY;
2565 }
2566
2567 if (RT_SUCCESS(rc))
2568 {
2569 /*
2570 * We don't need an additional client data area on the host,
2571 * because we're a class which can have members for that :-).
2572 */
2573 pTable->cbClient = sizeof(ClientState);
2574
2575 /* Limit pending calls to 8 pending per connection (doubt we need more than
2576 one). Map legacy clients to the root and limit kernel to 1. Use defaults
2577 for root and user clients. */
2578 for (uintptr_t i = 0; i < RT_ELEMENTS(pTable->acMaxClients); i++)
2579 pTable->acMaxCallsPerClient[i] = 8;
2580
2581 pTable->idxLegacyClientCategory = HGCM_CLIENT_CATEGORY_ROOT;
2582 pTable->acMaxClients[HGCM_CLIENT_CATEGORY_KERNEL] = 1;
2583
2584 /* Register functions. */
2585 pTable->pfnUnload = GstCtrlService::svcUnload;
2586 pTable->pfnConnect = GstCtrlService::svcConnect;
2587 pTable->pfnDisconnect = GstCtrlService::svcDisconnect;
2588 pTable->pfnCall = GstCtrlService::svcCall;
2589 pTable->pfnHostCall = GstCtrlService::svcHostCall;
2590 pTable->pfnSaveState = GstCtrlService::svcSaveState;
2591 pTable->pfnLoadState = GstCtrlService::svcLoadState;
2592 pTable->pfnRegisterExtension = GstCtrlService::svcRegisterExtension;
2593 pTable->pfnNotify = NULL;
2594
2595 /* Service specific initialization. */
2596 pTable->pvService = pService;
2597 }
2598 else
2599 {
2600 if (pService)
2601 {
2602 delete pService;
2603 pService = NULL;
2604 }
2605 }
2606 }
2607 }
2608
2609 LogFlowFunc(("Returning %Rrc\n", rc));
2610 return rc;
2611}
2612
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