VirtualBox

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

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

Guest Control: Update (first code for low level HGCM callback).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.6 KB
Line 
1/* $Id: service.cpp 28206 2010-04-12 13:48:49Z 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 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(VBOXHGCMCALLHANDLE callHandle, 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 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->uParmCount = cParms;
284 pBuf->pParms = (VBOXHGCMSVCPARM*)RTMemAlloc(sizeof(VBOXHGCMSVCPARM) * pBuf->uParmCount);
285 if (NULL == pBuf->pParms)
286 {
287 rc = VERR_NO_MEMORY;
288 }
289 else
290 {
291 for (uint32_t i = 0; i < pBuf->uParmCount; i++)
292 {
293 pBuf->pParms[i].type = paParms[i].type;
294 switch (paParms[i].type)
295 {
296 case VBOX_HGCM_SVC_PARM_32BIT:
297 pBuf->pParms[i].u.uint32 = paParms[i].u.uint32;
298 break;
299
300 case VBOX_HGCM_SVC_PARM_64BIT:
301 /* Not supported yet. */
302 break;
303
304 case VBOX_HGCM_SVC_PARM_PTR:
305 pBuf->pParms[i].u.pointer.size = paParms[i].u.pointer.size;
306 if (pBuf->pParms[i].u.pointer.size > 0)
307 {
308 pBuf->pParms[i].u.pointer.addr = RTMemAlloc(pBuf->pParms[i].u.pointer.size);
309 if (NULL == pBuf->pParms[i].u.pointer.addr)
310 {
311 rc = VERR_NO_MEMORY;
312 break;
313 }
314 else
315 memcpy(pBuf->pParms[i].u.pointer.addr,
316 paParms[i].u.pointer.addr,
317 pBuf->pParms[i].u.pointer.size);
318 }
319 break;
320
321 default:
322 break;
323 }
324 if (RT_FAILURE(rc))
325 break;
326 }
327 }
328 }
329 return rc;
330}
331
332/* Frees a buffered HGCM request. */
333void Service::paramBufferFree(PVBOXGUESTCTRPARAMBUFFER pBuf)
334{
335 AssertPtr(pBuf);
336 for (uint32_t i = 0; i < pBuf->uParmCount; i++)
337 {
338 switch (pBuf->pParms[i].type)
339 {
340 case VBOX_HGCM_SVC_PARM_PTR:
341 if (pBuf->pParms[i].u.pointer.size > 0)
342 RTMemFree(pBuf->pParms[i].u.pointer.addr);
343 break;
344 }
345 }
346 if (pBuf->uParmCount)
347 {
348 RTMemFree(pBuf->pParms);
349 pBuf->uParmCount = 0;
350 }
351}
352
353/* Assigns data from a buffered HGCM request to the current HGCM request. */
354int Service::paramBufferAssign(PVBOXGUESTCTRPARAMBUFFER pBuf, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
355{
356 AssertPtr(pBuf);
357 int rc = VINF_SUCCESS;
358 if (cParms != pBuf->uParmCount)
359 {
360 rc = VERR_INVALID_PARAMETER;
361 }
362 else
363 {
364 /** @todo Add check to verify if the HGCM request is the same *type* as the buffered one! */
365 for (uint32_t i = 0; i < pBuf->uParmCount; i++)
366 {
367 paParms[i].type = pBuf->pParms[i].type;
368 switch (paParms[i].type)
369 {
370 case VBOX_HGCM_SVC_PARM_32BIT:
371 paParms[i].u.uint32 = pBuf->pParms[i].u.uint32;
372 break;
373
374 case VBOX_HGCM_SVC_PARM_64BIT:
375 /* Not supported yet. */
376 break;
377
378 case VBOX_HGCM_SVC_PARM_PTR:
379 memcpy(paParms[i].u.pointer.addr,
380 pBuf->pParms[i].u.pointer.addr,
381 pBuf->pParms[i].u.pointer.size);
382 break;
383
384 default:
385 break;
386 }
387 }
388 }
389 return rc;
390}
391
392int Service::clientConnect(uint32_t u32ClientID, void *pvClient)
393{
394 LogFlowFunc(("New client (%ld) connected\n", u32ClientID));
395 return VINF_SUCCESS;
396}
397
398int Service::clientDisconnect(uint32_t u32ClientID, void *pvClient)
399{
400 LogFlowFunc(("Client (%ld) disconnected\n", u32ClientID));
401 return VINF_SUCCESS;
402}
403
404/*
405 * Either fills in parameters from a pending host command into our guest context or
406 * defer the guest call until we have something from the host.
407 */
408int Service::processHostMsg(VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
409{
410 int rc = VINF_SUCCESS;
411
412 if (cParms < 2)
413 {
414 LogFlowFunc(("Guest parameter buffer is too small!\n"));
415 rc = VERR_INVALID_PARAMETER;
416 }
417 else
418 {
419 /*
420 * If host command list is empty (nothing to do right now) just
421 * defer the call until we got something to do (makes the client
422 * wait, depending on the flags set).
423 */
424 if (mHostCmds.empty()) /* Command list is empty, defer ... */
425 rc = VINF_HGCM_ASYNC_EXECUTE;
426
427 if (rc != VINF_HGCM_ASYNC_EXECUTE)
428 {
429 /*
430 * Get the next unassigned host command in the list.
431 */
432 HostCmd curCmd = mHostCmds.front();
433 uint32_t uParmCount = curCmd.parmBuf.uParmCount;
434
435 /* Sufficient parameter space? */
436 if (uParmCount > cParms)
437 {
438 uint32_t uCmd = 0;
439 if (uParmCount)
440 curCmd.parmBuf.pParms[0].getUInt32(&uCmd);
441
442 paParms[0].setUInt32(/*uCmd*/ 1); /* Message ID */
443 paParms[1].setUInt32(uParmCount); /* Required parameters for message */
444
445 /*
446 * So this call apparently failed because the guest wanted to peek
447 * how much parameters it has to supply in order to successfully retrieve
448 * this command. Let's tell him so!
449 */
450 rc = VERR_TOO_MUCH_DATA;
451 }
452 else
453 {
454 rc = paramBufferAssign(&curCmd.parmBuf, cParms, paParms);
455 if (RT_SUCCESS(rc))
456 {
457 paramBufferFree(&curCmd.parmBuf);
458 mHostCmds.pop_front();
459 }
460 }
461 }
462 else
463 {
464 /* Call is deferred because of reasons above. */
465 mGuestWaiters.push_back(GuestCall(callHandle, GUEST_GET_HOST_MSG,
466 paParms, cParms, rc));
467 }
468 }
469 return rc;
470}
471
472/*
473 * Sends a command notification to the first waiting (deferred) client/guest in line in
474 * order to wake up and do some work.
475 */
476int Service::notifyGuest(GuestCall *pCall, uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
477{
478 AssertPtr(pCall);
479 int rc = VINF_SUCCESS;
480
481 int rc2 = processHostMsg(pCall->mHandle, pCall->mNumParms, pCall->mParms);
482 if (RT_SUCCESS(rc2))
483 rc2 = pCall->mRc;
484 AssertPtr(mpHelpers);
485 mpHelpers->pfnCallComplete(pCall->mHandle, rc2);
486 return rc;
487}
488
489int Service::notifyHost(VBOXHGCMCALLHANDLE callHandle, uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
490{
491 LogFlowFunc (("eFunction=%ld, cParms=%ld, paParms=%p\n",
492 eFunction, cParms, paParms));
493 HOSTCALLBACKDATA HostCallbackData;
494 HostCallbackData.u32Magic = HOSTCALLBACKMAGIC;
495
496 int rc = mpfnHostCallback (mpvHostData, 0 /*u32Function*/,
497 (void *)(&HostCallbackData),
498 sizeof(HostCallbackData));
499 LogFlowFunc (("returning %Rrc\n", rc));
500 return rc;
501}
502
503int Service::processCmd(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
504{
505 int rc = VINF_SUCCESS;
506
507 /* Some lazy guests to wake up which can process this command right now? */
508 if (!mGuestWaiters.empty())
509 {
510 GuestCall curCall = mGuestWaiters.front();
511 rc = notifyGuest(&curCall, eFunction, cParms, paParms);
512 mGuestWaiters.pop_front();
513 }
514 else /* No guests waiting, buffer it */
515 {
516 HostCmd newCmd;
517 rc = paramBufferAllocate(&newCmd.parmBuf, cParms, paParms);
518 if (RT_SUCCESS(rc))
519 {
520 mHostCmds.push_back(newCmd);
521
522 /* Limit list size by deleting oldest element. */
523 if (mHostCmds.size() > 256) /** @todo Use a define! */
524 mHostCmds.pop_front();
525 }
526 }
527 return rc;
528}
529
530/**
531 * Handle an HGCM service call.
532 * @copydoc VBOXHGCMSVCFNTABLE::pfnCall
533 * @note All functions which do not involve an unreasonable delay will be
534 * handled synchronously. If needed, we will add a request handler
535 * thread in future for those which do.
536 *
537 * @thread HGCM
538 */
539void Service::call(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID,
540 void * /* pvClient */, uint32_t eFunction, uint32_t cParms,
541 VBOXHGCMSVCPARM paParms[])
542{
543 int rc = VINF_SUCCESS;
544 LogFlowFunc(("u32ClientID = %d, fn = %d, cParms = %d, pparms = %d\n",
545 u32ClientID, eFunction, cParms, paParms));
546
547 ASMBreakpoint();
548
549 try
550 {
551 switch (eFunction)
552 {
553 /* The guest asks the host for the next messsage to process. */
554 case GUEST_GET_HOST_MSG:
555 LogFlowFunc(("GUEST_GET_HOST_MSG\n"));
556 rc = processHostMsg(callHandle, cParms, paParms);
557 break;
558
559 /* The guest notifies the host that some output at stdout is available. */
560 case GUEST_EXEC_SEND_STDOUT:
561 LogFlowFunc(("GUEST_EXEC_SEND_STDOUT\n"));
562 break;
563
564 /* The guest notifies the host that some output at stderr is available. */
565 case GUEST_EXEC_SEND_STDERR:
566 LogFlowFunc(("GUEST_EXEC_SEND_STDERR\n"));
567 break;
568
569 /* The guest notifies the host of the current client status. */
570 case GUEST_EXEC_SEND_STATUS:
571 LogFlowFunc(("SEND_STATUS\n"));
572 rc = notifyHost(callHandle, eFunction, cParms, paParms);
573 break;
574
575 default:
576 rc = VERR_NOT_SUPPORTED;
577 break;
578 }
579 /*
580 * If current call is not deferred, call the completion function.
581 */
582 if (rc != VINF_HGCM_ASYNC_EXECUTE)
583 {
584 mpHelpers->pfnCallComplete(callHandle, rc);
585 }
586 }
587 catch (std::bad_alloc)
588 {
589 rc = VERR_NO_MEMORY;
590 }
591 LogFlowFunc(("rc = %Rrc\n", rc));
592}
593
594/**
595 * Service call handler for the host.
596 * @copydoc VBOXHGCMSVCFNTABLE::pfnHostCall
597 * @thread hgcm
598 */
599int Service::hostCall(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
600{
601 int rc = VINF_SUCCESS;
602
603 ASMBreakpoint();
604
605 LogFlowFunc(("fn = %d, cParms = %d, pparms = %d\n",
606 eFunction, cParms, paParms));
607 try
608 {
609 switch (eFunction)
610 {
611 /* The host wants to execute something. */
612 case HOST_EXEC_CMD:
613 LogFlowFunc(("HOST_EXEC_CMD\n"));
614 rc = processCmd(eFunction, cParms, paParms);
615 break;
616
617 /* The host wants to send something to the guest's stdin pipe. */
618 case HOST_EXEC_SEND_STDIN:
619 LogFlowFunc(("HOST_EXEC_SEND_STDIN\n"));
620 break;
621
622 case HOST_EXEC_GET_STATUS:
623 LogFlowFunc(("HOST_EXEC_GET_STATUS\n"));
624 break;
625
626 default:
627 rc = VERR_NOT_SUPPORTED;
628 break;
629 }
630 }
631 catch (std::bad_alloc)
632 {
633 rc = VERR_NO_MEMORY;
634 }
635
636 LogFlowFunc(("rc = %Rrc\n", rc));
637 return rc;
638}
639
640int Service::uninit()
641{
642 int rc = VINF_SUCCESS;
643 return rc;
644}
645
646} /* namespace guestControl */
647
648using guestControl::Service;
649
650/**
651 * @copydoc VBOXHGCMSVCLOAD
652 */
653extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *ptable)
654{
655 int rc = VINF_SUCCESS;
656
657 LogFlowFunc(("ptable = %p\n", ptable));
658
659 if (!VALID_PTR(ptable))
660 {
661 rc = VERR_INVALID_PARAMETER;
662 }
663 else
664 {
665 LogFlowFunc(("ptable->cbSize = %d, ptable->u32Version = 0x%08X\n", ptable->cbSize, ptable->u32Version));
666
667 if ( ptable->cbSize != sizeof (VBOXHGCMSVCFNTABLE)
668 || ptable->u32Version != VBOX_HGCM_SVC_VERSION)
669 {
670 rc = VERR_VERSION_MISMATCH;
671 }
672 else
673 {
674 std::auto_ptr<Service> apService;
675 /* No exceptions may propogate outside. */
676 try {
677 apService = std::auto_ptr<Service>(new Service(ptable->pHelpers));
678 } catch (int rcThrown) {
679 rc = rcThrown;
680 } catch (...) {
681 rc = VERR_UNRESOLVED_ERROR;
682 }
683
684 if (RT_SUCCESS(rc))
685 {
686 /*
687 * We don't need an additional client data area on the host,
688 * because we're a class which can have members for that :-).
689 */
690 ptable->cbClient = 0;
691
692 /* Register functions. */
693 ptable->pfnUnload = Service::svcUnload;
694 ptable->pfnConnect = Service::svcConnect;
695 ptable->pfnDisconnect = Service::svcDisconnect;
696 ptable->pfnCall = Service::svcCall;
697 ptable->pfnHostCall = Service::svcHostCall;
698 ptable->pfnSaveState = NULL; /* The service is stateless, so the normal */
699 ptable->pfnLoadState = NULL; /* construction done before restoring suffices */
700 ptable->pfnRegisterExtension = Service::svcRegisterExtension;
701
702 /* Service specific initialization. */
703 ptable->pvService = apService.release();
704 }
705 }
706 }
707
708 LogFlowFunc(("returning %Rrc\n", rc));
709 return rc;
710}
711
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