VirtualBox

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

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

Guest Control: Update (introducing contexts for callbacks).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.7 KB
Line 
1/* $Id: service.cpp 28286 2010-04-14 10:02:30Z 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(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(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
490{
491 LogFlowFunc(("eFunction=%ld, cParms=%ld, paParms=%p\n",
492 eFunction, cParms, paParms));
493 int rc = VINF_SUCCESS;
494 if ( eFunction == GUEST_EXEC_SEND_STATUS
495 && cParms == 5)
496 {
497 HOSTEXECCALLBACKDATA data;
498 data.hdr.u32Magic = HOSTEXECCALLBACKDATAMAGIC;
499 paParms[0].getUInt32(&data.hdr.u32ContextID);
500
501 paParms[1].getUInt32(&data.u32PID);
502 paParms[2].getUInt32(&data.u32Status);
503 paParms[3].getUInt32(&data.u32Flags);
504 paParms[4].getPointer(&data.pvData, &data.cbData);
505
506 if (mpfnHostCallback)
507 rc = mpfnHostCallback(mpvHostData, eFunction,
508 (void *)(&data), sizeof(data));
509 }
510 else
511 rc = VERR_NOT_SUPPORTED;
512 LogFlowFunc(("returning %Rrc\n", rc));
513 return rc;
514}
515
516int Service::processCmd(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
517{
518 int rc = VINF_SUCCESS;
519
520 HostCmd newCmd;
521 rc = paramBufferAllocate(&newCmd.parmBuf, cParms, paParms);
522 if (RT_SUCCESS(rc))
523 {
524 mHostCmds.push_back(newCmd);
525
526 /* Limit list size by deleting oldest element. */
527 if (mHostCmds.size() > 256) /** @todo Use a define! */
528 mHostCmds.pop_front();
529 }
530
531 /* Some lazy guests to wake up which can process this command right now? */
532 if (!mGuestWaiters.empty())
533 {
534 GuestCall curCall = mGuestWaiters.front();
535 rc = notifyGuest(&curCall, eFunction, cParms, paParms);
536 mGuestWaiters.pop_front();
537 }
538 return rc;
539}
540
541/**
542 * Handle an HGCM service call.
543 * @copydoc VBOXHGCMSVCFNTABLE::pfnCall
544 * @note All functions which do not involve an unreasonable delay will be
545 * handled synchronously. If needed, we will add a request handler
546 * thread in future for those which do.
547 *
548 * @thread HGCM
549 */
550void Service::call(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID,
551 void * /* pvClient */, uint32_t eFunction, uint32_t cParms,
552 VBOXHGCMSVCPARM paParms[])
553{
554 int rc = VINF_SUCCESS;
555 LogFlowFunc(("u32ClientID = %d, fn = %d, cParms = %d, pparms = %d\n",
556 u32ClientID, eFunction, cParms, paParms));
557 try
558 {
559 switch (eFunction)
560 {
561 /* The guest asks the host for the next messsage to process. */
562 case GUEST_GET_HOST_MSG:
563 LogFlowFunc(("GUEST_GET_HOST_MSG\n"));
564 rc = processHostMsg(callHandle, cParms, paParms);
565 break;
566
567 /* The guest notifies the host that some output at stdout is available. */
568 case GUEST_EXEC_SEND_STDOUT:
569 LogFlowFunc(("GUEST_EXEC_SEND_STDOUT\n"));
570 break;
571
572 /* The guest notifies the host that some output at stderr is available. */
573 case GUEST_EXEC_SEND_STDERR:
574 LogFlowFunc(("GUEST_EXEC_SEND_STDERR\n"));
575 break;
576
577 /* The guest notifies the host of the current client status. */
578 case GUEST_EXEC_SEND_STATUS:
579 LogFlowFunc(("SEND_STATUS\n"));
580 rc = notifyHost(eFunction, cParms, paParms);
581 break;
582
583 default:
584 rc = VERR_NOT_SUPPORTED;
585 break;
586 }
587 /*
588 * If current call is not deferred, call the completion function.
589 */
590 if (rc != VINF_HGCM_ASYNC_EXECUTE)
591 {
592 mpHelpers->pfnCallComplete(callHandle, rc);
593 }
594 }
595 catch (std::bad_alloc)
596 {
597 rc = VERR_NO_MEMORY;
598 }
599 LogFlowFunc(("rc = %Rrc\n", rc));
600}
601
602/**
603 * Service call handler for the host.
604 * @copydoc VBOXHGCMSVCFNTABLE::pfnHostCall
605 * @thread hgcm
606 */
607int Service::hostCall(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
608{
609 int rc = VINF_SUCCESS;
610 LogFlowFunc(("fn = %d, cParms = %d, pparms = %d\n",
611 eFunction, cParms, paParms));
612 try
613 {
614 switch (eFunction)
615 {
616 /* The host wants to execute something. */
617 case HOST_EXEC_CMD:
618 LogFlowFunc(("HOST_EXEC_CMD\n"));
619 rc = processCmd(eFunction, cParms, paParms);
620 break;
621
622 /* The host wants to send something to the guest's stdin pipe. */
623 case HOST_EXEC_SEND_STDIN:
624 LogFlowFunc(("HOST_EXEC_SEND_STDIN\n"));
625 break;
626
627 case HOST_EXEC_GET_STATUS:
628 LogFlowFunc(("HOST_EXEC_GET_STATUS\n"));
629 break;
630
631 default:
632 rc = VERR_NOT_SUPPORTED;
633 break;
634 }
635 }
636 catch (std::bad_alloc)
637 {
638 rc = VERR_NO_MEMORY;
639 }
640
641 LogFlowFunc(("rc = %Rrc\n", rc));
642 return rc;
643}
644
645int Service::uninit()
646{
647 int rc = VINF_SUCCESS;
648 return rc;
649}
650
651} /* namespace guestControl */
652
653using guestControl::Service;
654
655/**
656 * @copydoc VBOXHGCMSVCLOAD
657 */
658extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *ptable)
659{
660 int rc = VINF_SUCCESS;
661
662 LogFlowFunc(("ptable = %p\n", ptable));
663
664 if (!VALID_PTR(ptable))
665 {
666 rc = VERR_INVALID_PARAMETER;
667 }
668 else
669 {
670 LogFlowFunc(("ptable->cbSize = %d, ptable->u32Version = 0x%08X\n", ptable->cbSize, ptable->u32Version));
671
672 if ( ptable->cbSize != sizeof (VBOXHGCMSVCFNTABLE)
673 || ptable->u32Version != VBOX_HGCM_SVC_VERSION)
674 {
675 rc = VERR_VERSION_MISMATCH;
676 }
677 else
678 {
679 std::auto_ptr<Service> apService;
680 /* No exceptions may propogate outside. */
681 try {
682 apService = std::auto_ptr<Service>(new Service(ptable->pHelpers));
683 } catch (int rcThrown) {
684 rc = rcThrown;
685 } catch (...) {
686 rc = VERR_UNRESOLVED_ERROR;
687 }
688
689 if (RT_SUCCESS(rc))
690 {
691 /*
692 * We don't need an additional client data area on the host,
693 * because we're a class which can have members for that :-).
694 */
695 ptable->cbClient = 0;
696
697 /* Register functions. */
698 ptable->pfnUnload = Service::svcUnload;
699 ptable->pfnConnect = Service::svcConnect;
700 ptable->pfnDisconnect = Service::svcDisconnect;
701 ptable->pfnCall = Service::svcCall;
702 ptable->pfnHostCall = Service::svcHostCall;
703 ptable->pfnSaveState = NULL; /* The service is stateless, so the normal */
704 ptable->pfnLoadState = NULL; /* construction done before restoring suffices */
705 ptable->pfnRegisterExtension = Service::svcRegisterExtension;
706
707 /* Service specific initialization. */
708 ptable->pvService = apService.release();
709 }
710 }
711 }
712
713 LogFlowFunc(("returning %Rrc\n", rc));
714 return rc;
715}
716
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