VirtualBox

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

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

Guest Control/VBoxService: Added support for cancel pending (blocking) calls; added support for properly stopping + shutting down main thread.

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