VirtualBox

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

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

Guest Control/HostService: VERR_NOT_SUPPORTED.

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