VirtualBox

source: vbox/trunk/src/VBox/HostServices/GuestControl/service.cpp@ 28557

Last change on this file since 28557 was 28557, checked in by vboxsync, 15 years ago

Guest Control: Update (first stuff for piping output).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.2 KB
Line 
1/* $Id: service.cpp 28557 2010-04-21 11:18:32Z vboxsync $ */
2/** @file
3 * Guest Control Service: Controlling the guest.
4 */
5
6/*
7 * Copyright (C) 2010 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/** @page pg_svc_guest_control Guest Control HGCM Service
23 *
24 * @todo Write up some nice text here.
25 */
26
27/*******************************************************************************
28* Header Files *
29*******************************************************************************/
30#define LOG_GROUP LOG_GROUP_HGCM
31#include <VBox/HostServices/GuestControlSvc.h>
32
33#include <VBox/log.h>
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/cpp/autores.h>
37#include <iprt/cpp/utils.h>
38#include <iprt/err.h>
39#include <iprt/mem.h>
40#include <iprt/req.h>
41#include <iprt/string.h>
42#include <iprt/thread.h>
43#include <iprt/time.h>
44
45#include <memory> /* for auto_ptr */
46#include <string>
47#include <list>
48
49#include "gctrl.h"
50
51namespace guestControl {
52
53/**
54 * Structure for holding a buffered host command
55 */
56struct HostCmd
57{
58 /** Dynamic structure for holding the HGCM parms */
59 VBOXGUESTCTRPARAMBUFFER parmBuf;
60};
61/** The host cmd list type */
62typedef std::list <HostCmd> HostCmdList;
63
64/**
65 * Structure for holding an uncompleted guest call
66 */
67struct GuestCall
68{
69 /** The call handle */
70 VBOXHGCMCALLHANDLE mHandle;
71 /** The function that was requested */
72 uint32_t mFunction;
73 /** The call parameters */
74 VBOXHGCMSVCPARM *mParms;
75 /** Number of parameters */
76 uint32_t mNumParms;
77 /** The default return value, used for passing warnings */
78 int mRc;
79
80 /** The standard constructor */
81 GuestCall() : mFunction(0) {}
82 /** The normal contructor */
83 GuestCall(VBOXHGCMCALLHANDLE aHandle, uint32_t aFunction,
84 VBOXHGCMSVCPARM aParms[], int cParms, int aRc)
85 : mHandle(aHandle), mFunction(aFunction), mParms(aParms),
86 mNumParms(cParms), mRc(aRc) {}
87};
88/** The guest call list type */
89typedef std::list <GuestCall> CallList;
90
91/**
92 * Class containing the shared information service functionality.
93 */
94class Service : public stdx::non_copyable
95{
96private:
97 /** Type definition for use in callback functions */
98 typedef Service SELF;
99 /** HGCM helper functions. */
100 PVBOXHGCMSVCHELPERS mpHelpers;
101 /** @todo we should have classes for thread and request handler thread */
102 /** Queue of outstanding property change notifications */
103 RTREQQUEUE *mReqQueue;
104 /** Request that we've left pending in a call to flushNotifications. */
105 PRTREQ mPendingDummyReq;
106 /** Thread for processing the request queue */
107 RTTHREAD mReqThread;
108 /** Tell the thread that it should exit */
109 bool volatile mfExitThread;
110 /** Callback function supplied by the host for notification of updates
111 * to properties */
112 PFNHGCMSVCEXT mpfnHostCallback;
113 /** User data pointer to be supplied to the host callback function */
114 void *mpvHostData;
115 /** The deferred calls list */
116 CallList mGuestWaiters;
117 /** The host command list */
118 HostCmdList mHostCmds;
119
120public:
121 explicit Service(PVBOXHGCMSVCHELPERS pHelpers)
122 : mpHelpers(pHelpers)
123 , mPendingDummyReq(NULL)
124 , mfExitThread(false)
125 , mpfnHostCallback(NULL)
126 , mpvHostData(NULL)
127 {
128 int rc = RTReqCreateQueue(&mReqQueue);
129#ifndef VBOX_GUEST_CTRL_TEST_NOTHREAD
130 if (RT_SUCCESS(rc))
131 rc = RTThreadCreate(&mReqThread, reqThreadFn, this, 0,
132 RTTHREADTYPE_MSG_PUMP, RTTHREADFLAGS_WAITABLE,
133 "GuestCtrlReq");
134#endif
135 if (RT_FAILURE(rc))
136 throw rc;
137 }
138
139 /**
140 * @copydoc VBOXHGCMSVCHELPERS::pfnUnload
141 * Simply deletes the service object
142 */
143 static DECLCALLBACK(int) svcUnload (void *pvService)
144 {
145 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
146 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
147 int rc = pSelf->uninit();
148 AssertRC(rc);
149 if (RT_SUCCESS(rc))
150 delete pSelf;
151 return rc;
152 }
153
154 /**
155 * @copydoc VBOXHGCMSVCHELPERS::pfnConnect
156 * Stub implementation of pfnConnect and pfnDisconnect.
157 */
158 static DECLCALLBACK(int) svcConnect (void *pvService,
159 uint32_t u32ClientID,
160 void *pvClient)
161 {
162 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
163 LogFlowFunc (("pvService=%p, u32ClientID=%u, pvClient=%p\n", pvService, u32ClientID, pvClient));
164 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
165 int rc = pSelf->clientConnect(u32ClientID, pvClient);
166 LogFlowFunc (("rc=%Rrc\n", rc));
167 return rc;
168 }
169
170 /**
171 * @copydoc VBOXHGCMSVCHELPERS::pfnConnect
172 * Stub implementation of pfnConnect and pfnDisconnect.
173 */
174 static DECLCALLBACK(int) svcDisconnect (void *pvService,
175 uint32_t u32ClientID,
176 void *pvClient)
177 {
178 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
179 LogFlowFunc (("pvService=%p, u32ClientID=%u, pvClient=%p\n", pvService, u32ClientID, pvClient));
180 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
181 int rc = pSelf->clientDisconnect(u32ClientID, pvClient);
182 LogFlowFunc (("rc=%Rrc\n", rc));
183 return rc;
184 }
185
186 /**
187 * @copydoc VBOXHGCMSVCHELPERS::pfnCall
188 * Wraps to the call member function
189 */
190 static DECLCALLBACK(void) svcCall (void * pvService,
191 VBOXHGCMCALLHANDLE callHandle,
192 uint32_t u32ClientID,
193 void *pvClient,
194 uint32_t u32Function,
195 uint32_t cParms,
196 VBOXHGCMSVCPARM paParms[])
197 {
198 AssertLogRelReturnVoid(VALID_PTR(pvService));
199 LogFlowFunc (("pvService=%p, callHandle=%p, u32ClientID=%u, pvClient=%p, u32Function=%u, cParms=%u, paParms=%p\n", pvService, callHandle, u32ClientID, pvClient, u32Function, cParms, paParms));
200 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
201 pSelf->call(callHandle, u32ClientID, pvClient, u32Function, cParms, paParms);
202 LogFlowFunc (("returning\n"));
203 }
204
205 /**
206 * @copydoc VBOXHGCMSVCHELPERS::pfnHostCall
207 * Wraps to the hostCall member function
208 */
209 static DECLCALLBACK(int) svcHostCall (void *pvService,
210 uint32_t u32Function,
211 uint32_t cParms,
212 VBOXHGCMSVCPARM paParms[])
213 {
214 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
215 LogFlowFunc (("pvService=%p, u32Function=%u, cParms=%u, paParms=%p\n", pvService, u32Function, cParms, paParms));
216 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
217 int rc = pSelf->hostCall(u32Function, cParms, paParms);
218 LogFlowFunc (("rc=%Rrc\n", rc));
219 return rc;
220 }
221
222 /**
223 * @copydoc VBOXHGCMSVCHELPERS::pfnRegisterExtension
224 * Installs a host callback for notifications of property changes.
225 */
226 static DECLCALLBACK(int) svcRegisterExtension (void *pvService,
227 PFNHGCMSVCEXT pfnExtension,
228 void *pvExtension)
229 {
230 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
231 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
232 pSelf->mpfnHostCallback = pfnExtension;
233 pSelf->mpvHostData = pvExtension;
234 return VINF_SUCCESS;
235 }
236private:
237 int paramBufferAllocate(PVBOXGUESTCTRPARAMBUFFER pBuf, uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
238 void paramBufferFree(PVBOXGUESTCTRPARAMBUFFER pBuf);
239 int paramBufferAssign(PVBOXGUESTCTRPARAMBUFFER pBuf, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
240 int prepareExecute(uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
241 static DECLCALLBACK(int) reqThreadFn(RTTHREAD ThreadSelf, void *pvUser);
242 int clientConnect(uint32_t u32ClientID, void *pvClient);
243 int clientDisconnect(uint32_t u32ClientID, void *pvClient);
244 int processHostMsg(VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
245 int notifyGuest(GuestCall *pCall, uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
246 int notifyHost(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
247 int processCmd(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
248 void call(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID,
249 void *pvClient, uint32_t eFunction, uint32_t cParms,
250 VBOXHGCMSVCPARM paParms[]);
251 int hostCall(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
252 int uninit();
253};
254
255
256/**
257 * Thread function for processing the request queue
258 * @copydoc FNRTTHREAD
259 */
260/* static */
261DECLCALLBACK(int) Service::reqThreadFn(RTTHREAD ThreadSelf, void *pvUser)
262{
263 SELF *pSelf = reinterpret_cast<SELF *>(pvUser);
264 while (!pSelf->mfExitThread)
265 RTReqProcess(pSelf->mReqQueue, RT_INDEFINITE_WAIT);
266 return VINF_SUCCESS;
267}
268
269/** @todo Write some nice doc headers! */
270/* Stores a HGCM request in an internal buffer (pEx). Needs to be freed later using execBufferFree(). */
271int Service::paramBufferAllocate(PVBOXGUESTCTRPARAMBUFFER pBuf, uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
272{
273 AssertPtr(pBuf);
274 int rc = VINF_SUCCESS;
275
276 /*
277 * Don't verify anything here (yet), because this function only buffers
278 * the HGCM data into an internal structure and reaches it back to the guest (client)
279 * in an unmodified state.
280 */
281 if (RT_SUCCESS(rc))
282 {
283 pBuf->uMsg = uMsg;
284 pBuf->uParmCount = cParms;
285 pBuf->pParms = (VBOXHGCMSVCPARM*)RTMemAlloc(sizeof(VBOXHGCMSVCPARM) * pBuf->uParmCount);
286 if (NULL == pBuf->pParms)
287 {
288 rc = VERR_NO_MEMORY;
289 }
290 else
291 {
292 for (uint32_t i = 0; i < pBuf->uParmCount; i++)
293 {
294 pBuf->pParms[i].type = paParms[i].type;
295 switch (paParms[i].type)
296 {
297 case VBOX_HGCM_SVC_PARM_32BIT:
298 pBuf->pParms[i].u.uint32 = paParms[i].u.uint32;
299 break;
300
301 case VBOX_HGCM_SVC_PARM_64BIT:
302 /* Not supported yet. */
303 break;
304
305 case VBOX_HGCM_SVC_PARM_PTR:
306 pBuf->pParms[i].u.pointer.size = paParms[i].u.pointer.size;
307 if (pBuf->pParms[i].u.pointer.size > 0)
308 {
309 pBuf->pParms[i].u.pointer.addr = RTMemAlloc(pBuf->pParms[i].u.pointer.size);
310 if (NULL == pBuf->pParms[i].u.pointer.addr)
311 {
312 rc = VERR_NO_MEMORY;
313 break;
314 }
315 else
316 memcpy(pBuf->pParms[i].u.pointer.addr,
317 paParms[i].u.pointer.addr,
318 pBuf->pParms[i].u.pointer.size);
319 }
320 break;
321
322 default:
323 break;
324 }
325 if (RT_FAILURE(rc))
326 break;
327 }
328 }
329 }
330 return rc;
331}
332
333/* Frees a buffered HGCM request. */
334void Service::paramBufferFree(PVBOXGUESTCTRPARAMBUFFER pBuf)
335{
336 AssertPtr(pBuf);
337 for (uint32_t i = 0; i < pBuf->uParmCount; i++)
338 {
339 switch (pBuf->pParms[i].type)
340 {
341 case VBOX_HGCM_SVC_PARM_PTR:
342 if (pBuf->pParms[i].u.pointer.size > 0)
343 RTMemFree(pBuf->pParms[i].u.pointer.addr);
344 break;
345 }
346 }
347 if (pBuf->uParmCount)
348 {
349 RTMemFree(pBuf->pParms);
350 pBuf->uParmCount = 0;
351 }
352}
353
354/* Assigns data from a buffered HGCM request to the current HGCM request. */
355int Service::paramBufferAssign(PVBOXGUESTCTRPARAMBUFFER pBuf, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
356{
357 AssertPtr(pBuf);
358 int rc = VINF_SUCCESS;
359 if (cParms != pBuf->uParmCount)
360 {
361 rc = VERR_INVALID_PARAMETER;
362 }
363 else
364 {
365 /** @todo Add check to verify if the HGCM request is the same *type* as the buffered one! */
366 for (uint32_t i = 0; i < pBuf->uParmCount; i++)
367 {
368 paParms[i].type = pBuf->pParms[i].type;
369 switch (paParms[i].type)
370 {
371 case VBOX_HGCM_SVC_PARM_32BIT:
372 paParms[i].u.uint32 = pBuf->pParms[i].u.uint32;
373 break;
374
375 case VBOX_HGCM_SVC_PARM_64BIT:
376 /* Not supported yet. */
377 break;
378
379 case VBOX_HGCM_SVC_PARM_PTR:
380 memcpy(paParms[i].u.pointer.addr,
381 pBuf->pParms[i].u.pointer.addr,
382 pBuf->pParms[i].u.pointer.size);
383 break;
384
385 default:
386 break;
387 }
388 }
389 }
390 return rc;
391}
392
393int Service::clientConnect(uint32_t u32ClientID, void *pvClient)
394{
395 LogFlowFunc(("New client (%ld) connected\n", u32ClientID));
396 return VINF_SUCCESS;
397}
398
399int Service::clientDisconnect(uint32_t u32ClientID, void *pvClient)
400{
401 LogFlowFunc(("Client (%ld) disconnected\n", u32ClientID));
402 return VINF_SUCCESS;
403}
404
405/*
406 * Either fills in parameters from a pending host command into our guest context or
407 * defer the guest call until we have something from the host.
408 */
409int Service::processHostMsg(VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
410{
411 int rc = VINF_SUCCESS;
412
413 if (cParms < 2)
414 {
415 LogFlowFunc(("Guest parameter buffer is too small!\n"));
416 rc = VERR_INVALID_PARAMETER;
417 }
418 else
419 {
420 /*
421 * If host command list is empty (nothing to do right now) just
422 * defer the call until we got something to do (makes the client
423 * wait, depending on the flags set).
424 */
425 if (mHostCmds.empty()) /* Command list is empty, defer ... */
426 rc = VINF_HGCM_ASYNC_EXECUTE;
427
428 if (rc != VINF_HGCM_ASYNC_EXECUTE)
429 {
430 /*
431 * Get the next unassigned host command in the list.
432 */
433 HostCmd curCmd = mHostCmds.front();
434 uint32_t uParmCount = curCmd.parmBuf.uParmCount;
435
436 /* Sufficient parameter space? */
437 if (uParmCount > cParms)
438 {
439 paParms[0].setUInt32(curCmd.parmBuf.uMsg); /* Message ID */
440 paParms[1].setUInt32(uParmCount); /* Required parameters for message */
441
442 /*
443 * So this call apparently failed because the guest wanted to peek
444 * how much parameters it has to supply in order to successfully retrieve
445 * this command. Let's tell him so!
446 */
447 rc = VERR_TOO_MUCH_DATA;
448 }
449 else
450 {
451 rc = paramBufferAssign(&curCmd.parmBuf, cParms, paParms);
452 if (RT_SUCCESS(rc))
453 {
454 paramBufferFree(&curCmd.parmBuf);
455 mHostCmds.pop_front();
456 }
457 }
458 }
459 else
460 {
461 /* Call is deferred because of reasons above. */
462 mGuestWaiters.push_back(GuestCall(callHandle, GUEST_GET_HOST_MSG,
463 paParms, cParms, rc));
464 }
465 }
466 return rc;
467}
468
469/*
470 * Sends a command notification to the first waiting (deferred) client/guest in line in
471 * order to wake up and do some work.
472 */
473int Service::notifyGuest(GuestCall *pCall, uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
474{
475 AssertPtr(pCall);
476 int rc = VINF_SUCCESS;
477
478 int rc2 = processHostMsg(pCall->mHandle, pCall->mNumParms, pCall->mParms);
479 if (RT_SUCCESS(rc2))
480 rc2 = pCall->mRc;
481 AssertPtr(mpHelpers);
482 mpHelpers->pfnCallComplete(pCall->mHandle, rc2);
483 return rc;
484}
485
486int Service::notifyHost(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
487{
488 LogFlowFunc(("eFunction=%ld, cParms=%ld, paParms=%p\n",
489 eFunction, cParms, paParms));
490 int rc = VINF_SUCCESS;
491 if ( eFunction == GUEST_EXEC_SEND_STATUS
492 && cParms == 5)
493 {
494 HOSTEXECCALLBACKDATA data;
495 data.hdr.u32Magic = HOSTEXECCALLBACKDATAMAGIC;
496 paParms[0].getUInt32(&data.hdr.u32ContextID);
497
498 paParms[1].getUInt32(&data.u32PID);
499 paParms[2].getUInt32(&data.u32Status);
500 paParms[3].getUInt32(&data.u32Flags);
501 paParms[4].getPointer(&data.pvData, &data.cbData);
502
503 if (mpfnHostCallback)
504 rc = mpfnHostCallback(mpvHostData, eFunction,
505 (void *)(&data), sizeof(data));
506 }
507 else if ( eFunction == GUEST_EXEC_SEND_OUTPUT
508 && cParms == 5)
509 {
510 HOSTEXECOUTCALLBACKDATA data;
511 data.hdr.u32Magic = HOSTEXECOUTCALLBACKDATAMAGIC;
512 paParms[0].getUInt32(&data.hdr.u32ContextID);
513
514 paParms[1].getUInt32(&data.u32PID);
515 paParms[2].getUInt32(&data.u32HandleId);
516 paParms[3].getUInt32(&data.u32Flags);
517 paParms[4].getPointer(&data.pvData, &data.cbData);
518
519 if (mpfnHostCallback)
520 rc = mpfnHostCallback(mpvHostData, eFunction,
521 (void *)(&data), sizeof(data));
522 }
523 else
524 rc = VERR_NOT_SUPPORTED;
525 LogFlowFunc(("returning %Rrc\n", rc));
526 return rc;
527}
528
529int Service::processCmd(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
530{
531 int rc = VINF_SUCCESS;
532
533 HostCmd newCmd;
534 rc = paramBufferAllocate(&newCmd.parmBuf, eFunction, cParms, paParms);
535 if (RT_SUCCESS(rc))
536 {
537 mHostCmds.push_back(newCmd);
538
539 /* Limit list size by deleting oldest element. */
540 if (mHostCmds.size() > 256) /** @todo Use a define! */
541 mHostCmds.pop_front();
542 }
543
544 /* Some lazy guests to wake up which can process this command right now? */
545 if (!mGuestWaiters.empty())
546 {
547 GuestCall curCall = mGuestWaiters.front();
548 rc = notifyGuest(&curCall, eFunction, cParms, paParms);
549 mGuestWaiters.pop_front();
550 }
551 return rc;
552}
553
554/**
555 * Handle an HGCM service call.
556 * @copydoc VBOXHGCMSVCFNTABLE::pfnCall
557 * @note All functions which do not involve an unreasonable delay will be
558 * handled synchronously. If needed, we will add a request handler
559 * thread in future for those which do.
560 *
561 * @thread HGCM
562 */
563void Service::call(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID,
564 void * /* pvClient */, uint32_t eFunction, uint32_t cParms,
565 VBOXHGCMSVCPARM paParms[])
566{
567 int rc = VINF_SUCCESS;
568 LogFlowFunc(("u32ClientID = %d, fn = %d, cParms = %d, pparms = %d\n",
569 u32ClientID, eFunction, cParms, paParms));
570 try
571 {
572 switch (eFunction)
573 {
574 /* The guest asks the host for the next messsage to process. */
575 case GUEST_GET_HOST_MSG:
576 LogFlowFunc(("GUEST_GET_HOST_MSG\n"));
577 rc = processHostMsg(callHandle, cParms, paParms);
578 break;
579
580 /* The guest notifies the host that some output at stdout/stderr is available. */
581 case GUEST_EXEC_SEND_OUTPUT:
582 LogFlowFunc(("GUEST_EXEC_SEND_OUTPUT\n"));
583 rc = notifyHost(eFunction, cParms, paParms);
584 break;
585
586 /* The guest notifies the host of the current client status. */
587 case GUEST_EXEC_SEND_STATUS:
588 LogFlowFunc(("SEND_STATUS\n"));
589 rc = notifyHost(eFunction, cParms, paParms);
590 break;
591
592 default:
593 rc = VERR_NOT_SUPPORTED;
594 break;
595 }
596 /*
597 * If current call is not deferred, call the completion function.
598 */
599 if (rc != VINF_HGCM_ASYNC_EXECUTE)
600 {
601 mpHelpers->pfnCallComplete(callHandle, rc);
602 }
603 }
604 catch (std::bad_alloc)
605 {
606 rc = VERR_NO_MEMORY;
607 }
608 LogFlowFunc(("rc = %Rrc\n", rc));
609}
610
611/**
612 * Service call handler for the host.
613 * @copydoc VBOXHGCMSVCFNTABLE::pfnHostCall
614 * @thread hgcm
615 */
616int Service::hostCall(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
617{
618 int rc = VINF_SUCCESS;
619 LogFlowFunc(("fn = %d, cParms = %d, pparms = %d\n",
620 eFunction, cParms, paParms));
621 try
622 {
623 switch (eFunction)
624 {
625 /* The host wants to execute something. */
626 case HOST_EXEC_CMD:
627 LogFlowFunc(("HOST_EXEC_CMD\n"));
628 rc = processCmd(eFunction, cParms, paParms);
629 break;
630
631 /* The host wants to send something to the guest's stdin pipe. */
632 case HOST_EXEC_SET_INPUT:
633 LogFlowFunc(("HOST_EXEC_SET_INPUT\n"));
634 break;
635
636 case HOST_EXEC_GET_OUTPUT:
637 LogFlowFunc(("HOST_EXEC_GET_OUTPUT\n"));
638 rc = processCmd(eFunction, cParms, paParms);
639 break;
640
641 default:
642 rc = VERR_NOT_SUPPORTED;
643 break;
644 }
645 }
646 catch (std::bad_alloc)
647 {
648 rc = VERR_NO_MEMORY;
649 }
650
651 LogFlowFunc(("rc = %Rrc\n", rc));
652 return rc;
653}
654
655int Service::uninit()
656{
657 int rc = VINF_SUCCESS;
658 return rc;
659}
660
661} /* namespace guestControl */
662
663using guestControl::Service;
664
665/**
666 * @copydoc VBOXHGCMSVCLOAD
667 */
668extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *ptable)
669{
670 int rc = VINF_SUCCESS;
671
672 LogFlowFunc(("ptable = %p\n", ptable));
673
674 if (!VALID_PTR(ptable))
675 {
676 rc = VERR_INVALID_PARAMETER;
677 }
678 else
679 {
680 LogFlowFunc(("ptable->cbSize = %d, ptable->u32Version = 0x%08X\n", ptable->cbSize, ptable->u32Version));
681
682 if ( ptable->cbSize != sizeof (VBOXHGCMSVCFNTABLE)
683 || ptable->u32Version != VBOX_HGCM_SVC_VERSION)
684 {
685 rc = VERR_VERSION_MISMATCH;
686 }
687 else
688 {
689 std::auto_ptr<Service> apService;
690 /* No exceptions may propogate outside. */
691 try {
692 apService = std::auto_ptr<Service>(new Service(ptable->pHelpers));
693 } catch (int rcThrown) {
694 rc = rcThrown;
695 } catch (...) {
696 rc = VERR_UNRESOLVED_ERROR;
697 }
698
699 if (RT_SUCCESS(rc))
700 {
701 /*
702 * We don't need an additional client data area on the host,
703 * because we're a class which can have members for that :-).
704 */
705 ptable->cbClient = 0;
706
707 /* Register functions. */
708 ptable->pfnUnload = Service::svcUnload;
709 ptable->pfnConnect = Service::svcConnect;
710 ptable->pfnDisconnect = Service::svcDisconnect;
711 ptable->pfnCall = Service::svcCall;
712 ptable->pfnHostCall = Service::svcHostCall;
713 ptable->pfnSaveState = NULL; /* The service is stateless, so the normal */
714 ptable->pfnLoadState = NULL; /* construction done before restoring suffices */
715 ptable->pfnRegisterExtension = Service::svcRegisterExtension;
716
717 /* Service specific initialization. */
718 ptable->pvService = apService.release();
719 }
720 }
721 }
722
723 LogFlowFunc(("returning %Rrc\n", rc));
724 return rc;
725}
726
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette