VirtualBox

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

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

Guest Control/Main: Faster (no polling on guest side), free data on shutdown.

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