Changeset 44863 in vbox for trunk/src/VBox/HostServices
- Timestamp:
- Feb 28, 2013 12:18:17 PM (12 years ago)
- svn:sync-xref-src-repo-rev:
- 84015
- Location:
- trunk/src/VBox
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/VBox-3.0/src/VBox 58652,70973 /branches/VBox-3.2/src/VBox 66309,66318 /branches/VBox-4.0/src/VBox 70873 /branches/VBox-4.1/src/VBox 74233,78414,78691,81841,82127 /branches/andy/guestctrl20/src/VBox 78916,78930 /branches/dsen/gui/src/VBox 79076-79078,79089,79109-79110,79112-79113,79127-79130,79134,79141,79151,79155,79157-79159,79193,79197 /branches/dsen/gui2/src/VBox 79224,79228,79233,79235,79258,79262-79263,79273,79341,79345,79354,79357,79387-79388,79559-79569,79572-79573,79578,79581-79582,79590-79591,79598-79599,79602-79603,79605-79606,79632,79635,79637,79644 /branches/dsen/gui3/src/VBox 79645-79692
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/src/VBox/HostServices/GuestControl/service.cpp
r44528 r44863 50 50 * host calls in order the client terminated/crashed (HGCM detects disconnected 51 51 * clients and reports it to this service's callback). 52 * 53 * Starting at VBox 4.2 the context ID itself consists of a session ID, an object 54 * ID (for example a process or file ID) and a count. This is necessary to not break 55 * compatibility between older hosts and to manage guest session on the host. 52 56 */ 53 57 … … 59 63 60 64 #include <VBox/log.h> 61 #include <iprt/asm.h> /* For ASMBreakpoint(). */62 65 #include <iprt/assert.h> 63 66 #include <iprt/cpp/autores.h> … … 65 68 #include <iprt/err.h> 66 69 #include <iprt/mem.h> 70 #include <iprt/list.h> 67 71 #include <iprt/req.h> 68 72 #include <iprt/string.h> … … 70 74 #include <iprt/time.h> 71 75 76 #include <map> 72 77 #include <memory> /* for auto_ptr */ 73 78 #include <string> … … 78 83 namespace guestControl { 79 84 85 /** Flag for indicating that the client only is interested in 86 * messages for specific contexts. */ 87 #define CLIENTSTATE_FLAG_CONTEXTFILTER RT_BIT(0) 88 89 /** 90 * Structure for maintaining a pending (that is, a deferred and not yet completed) 91 * client command. 92 */ 93 typedef struct ClientConnection 94 { 95 /** The call handle */ 96 VBOXHGCMCALLHANDLE mHandle; 97 /** Number of parameters */ 98 uint32_t mNumParms; 99 /** The call parameters */ 100 VBOXHGCMSVCPARM *mParms; 101 /** The standard constructor. */ 102 ClientConnection(void) : mHandle(0), mNumParms(0), mParms(NULL) {} 103 } ClientConnection; 104 105 /** 106 * Structure for holding a buffered host command which has 107 * not been processed yet. 108 */ 109 typedef struct HostCommand 110 { 111 RTLISTNODE Node; 112 113 uint32_t AddRef(void) 114 { 115 return ++mRefCount; 116 } 117 118 uint32_t Release(void) 119 { 120 LogFlowFunc(("Releasing CID=%RU32, refCount=%RU32\n", 121 mContextID, mRefCount)); 122 123 /* Release reference for current command. */ 124 Assert(mRefCount); 125 if (--mRefCount == 0) 126 Free(); 127 128 return mRefCount; 129 } 130 131 /** 132 * Allocates the command with an HGCM request. Needs to be free'd using Free(). 133 * 134 * @return IPRT status code. 135 * @param uMsg Message type. 136 * @param cParms Number of parameters of HGCM request. 137 * @param paParms Array of parameters of HGCM request. 138 */ 139 int Allocate(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 140 { 141 LogFlowFunc(("Allocating uMsg=%RU32, cParms=%RU32, paParms=%p\n", 142 uMsg, cParms, paParms)); 143 144 if (!cParms) /* At least one parameter (context ID) must be present. */ 145 return VERR_INVALID_PARAMETER; 146 147 AssertPtrReturn(paParms, VERR_INVALID_POINTER); 148 149 /* Paranoia. */ 150 if (cParms > 256) 151 cParms = 256; 152 153 int rc = VINF_SUCCESS; 154 155 /* 156 * Don't verify anything here (yet), because this function only buffers 157 * the HGCM data into an internal structure and reaches it back to the guest (client) 158 * in an unmodified state. 159 */ 160 mMsgType = uMsg; 161 mParmCount = cParms; 162 if (mParmCount) 163 { 164 mpParms = (VBOXHGCMSVCPARM*)RTMemAllocZ(sizeof(VBOXHGCMSVCPARM) * mParmCount); 165 if (NULL == mpParms) 166 rc = VERR_NO_MEMORY; 167 } 168 169 if (RT_SUCCESS(rc)) 170 { 171 for (uint32_t i = 0; i < mParmCount; i++) 172 { 173 mpParms[i].type = paParms[i].type; 174 switch (paParms[i].type) 175 { 176 case VBOX_HGCM_SVC_PARM_32BIT: 177 mpParms[i].u.uint32 = paParms[i].u.uint32; 178 break; 179 180 case VBOX_HGCM_SVC_PARM_64BIT: 181 /* Not supported yet. */ 182 break; 183 184 case VBOX_HGCM_SVC_PARM_PTR: 185 mpParms[i].u.pointer.size = paParms[i].u.pointer.size; 186 if (mpParms[i].u.pointer.size > 0) 187 { 188 mpParms[i].u.pointer.addr = RTMemAlloc(mpParms[i].u.pointer.size); 189 if (NULL == mpParms[i].u.pointer.addr) 190 { 191 rc = VERR_NO_MEMORY; 192 break; 193 } 194 else 195 memcpy(mpParms[i].u.pointer.addr, 196 paParms[i].u.pointer.addr, 197 mpParms[i].u.pointer.size); 198 } 199 else 200 { 201 /* Size is 0 -- make sure we don't have any pointer. */ 202 mpParms[i].u.pointer.addr = NULL; 203 } 204 break; 205 206 default: 207 break; 208 } 209 if (RT_FAILURE(rc)) 210 break; 211 } 212 } 213 214 if (RT_SUCCESS(rc)) 215 { 216 /* 217 * Assume that the context ID *always* is the first parameter, 218 * assign the context ID to the command. 219 */ 220 rc = mpParms[0].getUInt32(&mContextID); 221 } 222 223 LogFlowFunc(("Returned with rc=%Rrc\n", rc)); 224 return rc; 225 } 226 227 /** 228 * Frees the buffered HGCM request. 229 * 230 * @return IPRT status code. 231 */ 232 void Free(void) 233 { 234 AssertMsg(mRefCount == 0, ("Command still being used by a client (%RU32 refs), cannot free yet\n", 235 mRefCount)); 236 237 LogFlowFunc(("Freeing host command CID=%RU32, mMsgType=%RU32, mParmCount=%RU32, mpParms=%p\n", 238 mContextID, mMsgType, mParmCount, mpParms)); 239 240 for (uint32_t i = 0; i < mParmCount; i++) 241 { 242 switch (mpParms[i].type) 243 { 244 case VBOX_HGCM_SVC_PARM_PTR: 245 if (mpParms[i].u.pointer.size > 0) 246 RTMemFree(mpParms[i].u.pointer.addr); 247 break; 248 } 249 } 250 251 if (mpParms) 252 RTMemFree(mpParms); 253 254 mParmCount = 0; 255 } 256 257 /** 258 * Copies data from the buffered HGCM request to the current HGCM request. 259 * 260 * @return IPRT status code. 261 * @param paDstParms Array of parameters of HGCM request to fill the data into. 262 * @param cPDstarms Number of parameters the HGCM request can handle. 263 * @param pSrcBuf Parameter buffer to assign. 264 */ 265 int CopyTo(VBOXHGCMSVCPARM paDstParms[], uint32_t cDstParms) const 266 { 267 int rc = VINF_SUCCESS; 268 if (cDstParms != mParmCount) 269 { 270 LogFlowFunc(("Parameter count does not match (got %RU32, expected %RU32)\n", 271 cDstParms, mParmCount)); 272 rc = VERR_INVALID_PARAMETER; 273 } 274 else 275 { 276 for (uint32_t i = 0; i < mParmCount; i++) 277 { 278 if (paDstParms[i].type != mpParms[i].type) 279 { 280 LogFlowFunc(("Parameter %RU32 type mismatch (got %RU32, expected %RU32)\n", 281 i, paDstParms[i].type, mpParms[i].type)); 282 rc = VERR_INVALID_PARAMETER; 283 } 284 else 285 { 286 switch (mpParms[i].type) 287 { 288 case VBOX_HGCM_SVC_PARM_32BIT: 289 paDstParms[i].u.uint32 = mpParms[i].u.uint32; 290 break; 291 292 case VBOX_HGCM_SVC_PARM_PTR: 293 { 294 if (!mpParms[i].u.pointer.size) 295 continue; /* Only copy buffer if there actually is something to copy. */ 296 297 if (!paDstParms[i].u.pointer.addr) 298 rc = VERR_INVALID_PARAMETER; 299 300 if (paDstParms[i].u.pointer.size < mpParms[i].u.pointer.size) 301 rc = VERR_BUFFER_OVERFLOW; 302 303 if (RT_SUCCESS(rc)) 304 { 305 memcpy(paDstParms[i].u.pointer.addr, 306 mpParms[i].u.pointer.addr, 307 mpParms[i].u.pointer.size); 308 } 309 310 break; 311 } 312 313 case VBOX_HGCM_SVC_PARM_64BIT: 314 /* Fall through is intentional. */ 315 default: 316 LogFlowFunc(("Parameter %RU32 of type %RU32 is not supported yet\n", 317 i, mpParms[i].type)); 318 rc = VERR_NOT_SUPPORTED; 319 break; 320 } 321 } 322 323 if (RT_FAILURE(rc)) 324 { 325 LogFlowFunc(("Parameter %RU32 invalid (rc=%Rrc), refusing\n", 326 i, rc)); 327 break; 328 } 329 } 330 } 331 332 return rc; 333 } 334 335 int AssignToConnection(const ClientConnection *pConnection) 336 { 337 int rc; 338 339 LogFlowFunc(("mMsgType=%RU32, mParmCount=%RU32, mpParms=%p\n", 340 mMsgType, mParmCount, mpParms)); 341 342 /* Does the current host command need more parameter space which 343 * the client does not provide yet? */ 344 if (mParmCount > pConnection->mNumParms) 345 { 346 pConnection->mParms[0].setUInt32(mMsgType); /* Message ID */ 347 pConnection->mParms[1].setUInt32(mParmCount); /* Required parameters for message */ 348 349 /* 350 * So this call apparently failed because the guest wanted to peek 351 * how much parameters it has to supply in order to successfully retrieve 352 * this command. Let's tell him so! 353 */ 354 rc = VERR_TOO_MUCH_DATA; 355 } 356 else 357 { 358 rc = CopyTo(pConnection->mParms, pConnection->mNumParms); 359 360 /* Has there been enough parameter space but the wrong parameter types 361 * were submitted -- maybe the client was just asking for the next upcoming 362 * host message? 363 * 364 * Note: To keep this compatible to older clients we return VERR_TOO_MUCH_DATA 365 * in every case. */ 366 if (RT_FAILURE(rc)) 367 rc = VERR_TOO_MUCH_DATA; 368 } 369 370 LogFlowFunc(("Returned with rc=%Rrc\n", rc)); 371 return rc; 372 } 373 374 /** Reference count for keeping track how many connected 375 * clients still need to process this command until it can 376 * be removed. */ 377 uint32_t mRefCount; 378 /** The context ID this command belongs to. Will be extracted 379 * *always* from HGCM parameter [0]. */ 380 uint32_t mContextID; 381 /** Dynamic structure for holding the HGCM parms */ 382 uint32_t mMsgType; 383 uint32_t mParmCount; 384 PVBOXHGCMSVCPARM mpParms; 385 } HostCommand; 386 387 /** 388 * Per-client structure used for book keeping/state tracking a 389 * certain host command. 390 */ 391 typedef struct ClientContext 392 { 393 /* Pointer to list node of this command. */ 394 HostCommand *mpHostCmd; 395 /** The standard constructor. */ 396 ClientContext(void) : mpHostCmd(NULL) {} 397 /** Internal constrcutor. */ 398 ClientContext(HostCommand *pHostCmd) : mpHostCmd(pHostCmd) {} 399 } ClientContext; 400 typedef std::map< uint32_t, ClientContext > ClientContextMap; 401 typedef std::map< uint32_t, ClientContext >::iterator ClientContextMapIter; 402 typedef std::map< uint32_t, ClientContext >::const_iterator ClientContextMapIterConst; 403 80 404 /** 81 405 * Structure for holding all clients with their 82 406 * generated host contexts. This is necessary for 83 * maintaining the relationship between a client and its context IDs. 84 */ 85 struct ClientContexts 86 { 87 /** This client ID. */ 88 uint32_t mClientID; 89 /** The list of contexts a client is assigned to. */ 90 std::list< uint32_t > mContextList; 91 92 /** The normal constructor. */ 93 ClientContexts(uint32_t aClientID) 94 : mClientID(aClientID) {} 95 }; 96 /** The client list + iterator type */ 97 typedef std::list< ClientContexts > ClientContextsList; 98 typedef std::list< ClientContexts >::iterator ClientContextsListIter; 99 typedef std::list< ClientContexts >::const_iterator ClientContextsListIterConst; 100 101 /** 102 * Structure for holding an uncompleted guest call. 103 */ 104 struct ClientWaiter 105 { 106 /** Client ID; a client can have multiple handles! */ 107 uint32_t mClientID; 108 /** The call handle */ 109 VBOXHGCMCALLHANDLE mHandle; 110 /** The call parameters */ 111 VBOXHGCMSVCPARM *mParms; 112 /** Number of parameters */ 113 uint32_t mNumParms; 114 115 /** The standard constructor. */ 116 ClientWaiter() : mClientID(0), mHandle(0), mParms(NULL), mNumParms(0) {} 117 /** The normal constructor. */ 118 ClientWaiter(uint32_t aClientID, VBOXHGCMCALLHANDLE aHandle, 119 VBOXHGCMSVCPARM aParms[], uint32_t cParms) 120 : mClientID(aClientID), mHandle(aHandle), mParms(aParms), mNumParms(cParms) {} 121 }; 122 /** The guest call list type */ 123 typedef std::list< ClientWaiter > ClientWaiterList; 124 typedef std::list< ClientWaiter >::iterator CallListIter; 125 typedef std::list< ClientWaiter >::const_iterator CallListIterConst; 126 127 /** 128 * Structure for holding a buffered host command. 129 */ 130 typedef struct VBOXGUESTCTRLHOSTCMD 131 { 132 /** The context ID this command belongs to. Will be extracted 133 * from the HGCM parameters. */ 134 uint32_t mContextID; 407 * maintaining the relationship between a client and its context ID(s). 408 */ 409 typedef struct ClientState 410 { 411 ClientState(PVBOXHGCMSVCHELPERS pSvcHelpers) 412 : mSvcHelpers(pSvcHelpers), mpHostCmd(NULL), 413 mFlags(0), mContextFilter(0), mIsPending(false), 414 mHostCmdTries(0), mHostCmdRc(VINF_SUCCESS) {} 415 416 ClientState(void) 417 : mSvcHelpers(NULL), mpHostCmd(NULL), 418 mFlags(0), mContextFilter(0), mIsPending(false), 419 mHostCmdTries(0), mHostCmdRc(VINF_SUCCESS) {} 420 421 bool WantsHostCommand(const HostCommand *pHostCmd) const 422 { 423 AssertPtrReturn(pHostCmd, false); 424 425 /* 426 * If a sesseion filter is set, only obey those sessions we're interested in. 427 */ 428 if (mFlags & CLIENTSTATE_FLAG_CONTEXTFILTER) 429 { 430 if (VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(pHostCmd->mContextID) == mContextFilter) 431 return true; 432 } 433 else /* Client is interested in all commands. */ 434 return true; 435 436 return false; 437 } 438 439 int SetPending(const ClientConnection *pConnection) 440 { 441 AssertPtrReturn(pConnection, VERR_INVALID_POINTER); 442 443 if (mpHostCmd == NULL) 444 { 445 AssertMsg(mIsPending == false, 446 ("Client %p already is pending but tried to receive a new host command\n", this)); 447 448 mPending.mHandle = pConnection->mHandle; 449 mPending.mNumParms = pConnection->mNumParms; 450 mPending.mParms = pConnection->mParms; 451 452 mIsPending = true; 453 454 LogFlowFunc(("Client now is in pending mode\n")); 455 456 /* 457 * Signal that we don't and can't return yet. 458 */ 459 return VINF_HGCM_ASYNC_EXECUTE; 460 } 461 462 /* 463 * Signal that there already is a connection pending. 464 * Shouldn't happen in daily usage. 465 */ 466 AssertMsgFailed(("Client already has a connection pending\n")); 467 return VERR_SIGNAL_PENDING; 468 } 469 470 int Run(const ClientConnection *pConnection, 471 const RTLISTANCHOR *pHostCmdList) 472 { 473 int rc = VINF_SUCCESS; 474 475 LogFlowFunc(("Client pConnection=%p, pHostCmdList=%p\n", 476 pConnection, pHostCmdList)); 477 LogFlowFunc(("Client hostCmd=%p, mHostCmdRc=%Rrc, mHostCmdTries=%RU32\n", 478 mpHostCmd, mHostCmdRc, mHostCmdTries)); 479 480 /* Do we have a current command? */ 481 if (mpHostCmd) 482 { 483 bool fRemove = false; 484 if (RT_FAILURE(mHostCmdRc)) 485 { 486 mHostCmdTries++; 487 488 /* 489 * If the client understood the message but supplied too little buffer space 490 * don't send this message again and drop it after 3 unsuccessful attempts. 491 * The host then should take care of next actions (maybe retry it with a smaller buffer). 492 */ 493 if ( mHostCmdRc == VERR_TOO_MUCH_DATA 494 && mHostCmdTries >= 3) 495 { 496 fRemove = true; 497 } 498 /* Client did not understand the message or something else weird happened. Try again one 499 * more time and drop it if it didn't get handled then. */ 500 else if (mHostCmdTries > 1) 501 fRemove = true; 502 } 503 else 504 fRemove = true; /* Everything went fine, remove it. */ 505 506 LogFlowFunc(("Client tried CID=%RU32 for %RU32 times, (last result=%Rrc, fRemove=%RTbool)\n", 507 mpHostCmd->mContextID, mHostCmdTries, mHostCmdRc, fRemove)); 508 509 if (fRemove) 510 { 511 LogFlowFunc(("Client removes itself from command CID=%RU32\n", 512 mpHostCmd->mContextID)); 513 514 /* Remove command from context map. */ 515 mContextMap.erase(mpHostCmd->mContextID); 516 517 /* Release reference for current command. */ 518 if (mpHostCmd->Release() == 0) 519 { 520 LogFlowFunc(("Destroying and removing command CID=%RU32 from list\n", 521 mpHostCmd->mContextID)); 522 523 /* Last reference removes the command from the list. */ 524 RTListNodeRemove(&mpHostCmd->Node); 525 526 RTMemFree(mpHostCmd); 527 mpHostCmd = NULL; 528 } 529 530 /* Reset everything else. */ 531 mHostCmdRc = VINF_SUCCESS; 532 mHostCmdTries = 0; 533 } 534 } 535 536 /* ... or don't we have one (anymore?) Try getting a new one to process now. */ 537 if (mpHostCmd == NULL) 538 { 539 /* Get the next host command the clienet is interested in. */ 540 bool fFoundCmd = false; 541 HostCommand *pCurCmd; 542 RTListForEach(pHostCmdList, pCurCmd, HostCommand, Node) 543 { 544 fFoundCmd = WantsHostCommand(pCurCmd); 545 if (fFoundCmd) 546 { 547 mpHostCmd = pCurCmd; 548 AssertPtr(mpHostCmd); 549 mpHostCmd->AddRef(); 550 551 /* Create a command context to keep track of client-specific 552 * information about a certain command. */ 553 Assert(mContextMap.find(mpHostCmd->mContextID) == mContextMap.end()); 554 mContextMap[mpHostCmd->mContextID] = ClientContext(mpHostCmd); 555 /** @todo Exception handling! */ 556 557 LogFlowFunc(("Assigning next host comamnd CID=%RU32, cmdType=%RU32, cmdParms=%RU32, new refCount=%RU32\n", 558 mpHostCmd->mContextID, mpHostCmd->mMsgType, mpHostCmd->mParmCount, mpHostCmd->mRefCount)); 559 break; 560 } 561 } 562 563 LogFlowFunc(("Client %s new command\n", 564 fFoundCmd ? "found" : "did not find a")); 565 566 /* If no new command was found, set client into pending state. */ 567 if (!fFoundCmd) 568 rc = SetPending(pConnection); 569 } 570 571 if (mpHostCmd) 572 { 573 AssertPtr(mpHostCmd); 574 mHostCmdRc = SendReply(pConnection, mpHostCmd); 575 if (RT_FAILURE(mHostCmdRc)) 576 { 577 LogFlowFunc(("Processing command CID=%RU32 ended with rc=%Rrc\n", 578 mpHostCmd->mContextID, mHostCmdRc)); 579 } 580 581 if (RT_SUCCESS(rc)) 582 rc = mHostCmdRc; 583 } 584 585 LogFlowFunc(("Returned with rc=%Rrc\n", rc)); 586 return rc; 587 } 588 589 int RunNow(const ClientConnection *pConnection, 590 const PRTLISTANCHOR pHostCmdList) 591 { 592 AssertPtrReturn(pConnection, VERR_INVALID_POINTER); 593 AssertPtrReturn(pHostCmdList, VERR_INVALID_POINTER); 594 595 AssertMsgReturn(!mIsPending, ("Can't use another connection when client still is in pending mode\n"), 596 VERR_INVALID_PARAMETER); 597 598 int rc = Run(pConnection, pHostCmdList); 599 600 LogFlowFunc(("Returned with rc=%Rrc\n")); 601 return rc; 602 } 603 604 int Wakeup(const PRTLISTANCHOR pHostCmdList) 605 { 606 AssertMsgReturn(mIsPending, ("Cannot wake up a client which is not in pending mode\n"), 607 VERR_INVALID_PARAMETER); 608 609 int rc = Run(&mPending, pHostCmdList); 610 611 /* Reset pending state. */ 612 mIsPending = false; 613 614 LogFlowFunc(("Returned with rc=%Rrc\n")); 615 return rc; 616 } 617 618 int CancelWaiting(int rcPending) 619 { 620 LogFlowFunc(("Cancelling waiting with %Rrc, isPending=%RTbool, pendingNumParms=%RU32, flags=%x\n", 621 rcPending, mIsPending, mPending.mNumParms, mFlags)); 622 623 if ( mIsPending 624 && mPending.mNumParms >= 2) 625 { 626 mPending.mParms[0].setUInt32(HOST_CANCEL_PENDING_WAITS); /* Message ID. */ 627 mPending.mParms[1].setUInt32(0); /* Required parameters for message. */ 628 629 AssertPtr(mSvcHelpers); 630 mSvcHelpers->pfnCallComplete(mPending.mHandle, rcPending); 631 632 mIsPending = false; 633 } 634 635 return VINF_SUCCESS; 636 } 637 638 int SendReply(const ClientConnection *pConnection, 639 HostCommand *pHostCmd) 640 { 641 AssertPtrReturn(pConnection, VERR_INVALID_POINTER); 642 AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER); 643 644 /* Try assigning the host command to the client and store the 645 * result code for later use. */ 646 int rc = pHostCmd->AssignToConnection(pConnection); 647 648 /* In any case the client did something, so wake up and remove from list. */ 649 AssertPtr(mSvcHelpers); 650 mSvcHelpers->pfnCallComplete(pConnection->mHandle, rc); 651 652 LogFlowFunc(("pConnection=%p, pHostCmd=%p, rc=%Rrc\n", 653 pConnection, pHostCmd, rc)); 654 return rc; 655 } 656 657 PVBOXHGCMSVCHELPERS mSvcHelpers; 658 /** Client flags. @sa CLIENTSTATE_FLAG_ flags. */ 659 uint32_t mFlags; 660 /** The context ID filter, based on the flags set. */ 661 uint32_t mContextFilter; 662 /** Map containing all context IDs a client is assigned to. */ 663 //std::map< uint32_t, ClientContext > mContextMap; 664 /** Pointer to current host command to process. */ 665 HostCommand *mpHostCmd; 666 /** Last (most recent) rc after handling the 667 * host command. */ 668 int mHostCmdRc; 135 669 /** How many times the host service has tried to deliver this 136 * command to the guest. */137 uint32_t m Tries;138 /** Dynamic structure for holding the HGCM parms*/139 VBOXGUESTCTRPARAMBUFFER mParmBuf;140 141 /** The standard constructor. */142 VBOXGUESTCTRLHOSTCMD() : mContextID(0), mTries(0) {}143 };144 /** The host cmd list + iterator type */ 145 typedef std:: list< VBOXGUESTCTRLHOSTCMD > HostCmdList;146 typedef std:: list< VBOXGUESTCTRLHOSTCMD >::iterator HostCmdListIter;147 typedef std:: list< VBOXGUESTCTRLHOSTCMD >::const_iterator HostCmdListIterConst;670 * command to the according client. */ 671 uint32_t mHostCmdTries; 672 /** Map containing all context IDs a client is assigned to. */ 673 ClientContextMap mContextMap; 674 /** Flag indicating whether the client currently is pending. */ 675 bool mIsPending; 676 /** The client's pending connection. */ 677 ClientConnection mPending; 678 } ClientState; 679 typedef std::map< uint32_t, ClientState > ClientStateMap; 680 typedef std::map< uint32_t, ClientState >::iterator ClientStateMapIter; 681 typedef std::map< uint32_t, ClientState >::const_iterator ClientStateMapIterConst; 148 682 149 683 /** … … 152 686 class Service : public RTCNonCopyable 153 687 { 688 154 689 private: 690 155 691 /** Type definition for use in callback functions. */ 156 692 typedef Service SELF; 157 693 /** HGCM helper functions. */ 158 694 PVBOXHGCMSVCHELPERS mpHelpers; 159 /* 695 /** 160 696 * Callback function supplied by the host for notification of updates 161 697 * to properties. … … 164 700 /** User data pointer to be supplied to the host callback function. */ 165 701 void *mpvHostData; 166 /** The deferred calls list. */ 167 ClientWaiterList mClientWaiterList; 168 /** The host command list. */ 169 HostCmdList mHostCmds; 170 /** Client contexts list. */ 171 ClientContextsList mClientContextsList; 172 /** Number of connected clients. */ 173 uint32_t mNumClients; 702 /** List containing all buffered host commands. */ 703 RTLISTANCHOR mHostCmdList; 704 /** Map containing all connected clients. The primary key contains 705 * the HGCM client ID to identify the client. */ 706 ClientStateMap mClientStateMap; 174 707 public: 175 708 explicit Service(PVBOXHGCMSVCHELPERS pHelpers) … … 177 710 , mpfnHostCallback(NULL) 178 711 , mpvHostData(NULL) 179 , mNumClients(0)180 {712 { 713 RTListInit(&mHostCmdList); 181 714 } 182 715 … … 207 740 LogFlowFunc (("pvService=%p, u32ClientID=%u, pvClient=%p\n", pvService, u32ClientID, pvClient)); 208 741 SELF *pSelf = reinterpret_cast<SELF *>(pvService); 209 int rc = pSelf->clientConnect(u32ClientID, pvClient); 210 LogFlowFunc (("rc=%Rrc\n", rc)); 211 return rc; 742 return pSelf->clientConnect(u32ClientID, pvClient); 212 743 } 213 744 … … 223 754 LogFlowFunc (("pvService=%p, u32ClientID=%u, pvClient=%p\n", pvService, u32ClientID, pvClient)); 224 755 SELF *pSelf = reinterpret_cast<SELF *>(pvService); 225 int rc = pSelf->clientDisconnect(u32ClientID, pvClient); 226 LogFlowFunc (("rc=%Rrc\n", rc)); 227 return rc; 756 return pSelf->clientDisconnect(u32ClientID, pvClient); 228 757 } 229 758 … … 241 770 { 242 771 AssertLogRelReturnVoid(VALID_PTR(pvService)); 243 LogFlowFunc (("pvService=%p, callHandle=%p, u32ClientID=%u, pvClient=%p, u32Function=%u, cParms=%u, paParms=%p\n", pvService, callHandle, u32ClientID, pvClient, u32Function, cParms, paParms)); 772 LogFlowFunc (("pvService=%p, callHandle=%p, u32ClientID=%u, pvClient=%p, u32Function=%u, cParms=%u, paParms=%p\n", 773 pvService, callHandle, u32ClientID, pvClient, u32Function, cParms, paParms)); 244 774 SELF *pSelf = reinterpret_cast<SELF *>(pvService); 245 775 pSelf->call(callHandle, u32ClientID, pvClient, u32Function, cParms, paParms); 246 LogFlowFunc (("returning\n"));247 776 } 248 777 … … 259 788 LogFlowFunc (("pvService=%p, u32Function=%u, cParms=%u, paParms=%p\n", pvService, u32Function, cParms, paParms)); 260 789 SELF *pSelf = reinterpret_cast<SELF *>(pvService); 261 int rc = pSelf->hostCall(u32Function, cParms, paParms); 262 LogFlowFunc (("rc=%Rrc\n", rc)); 263 return rc; 790 return pSelf->hostCall(u32Function, cParms, paParms); 264 791 } 265 792 … … 278 805 return VINF_SUCCESS; 279 806 } 807 280 808 private: 281 int paramBufferAllocate(PVBOXGUESTCTRPARAMBUFFER pBuf, uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 282 void paramBufferFree(PVBOXGUESTCTRPARAMBUFFER pBuf); 283 int paramBufferAssign(VBOXHGCMSVCPARM paDstParms[], uint32_t cDstParms, const VBOXGUESTCTRPARAMBUFFER *pSrcBuf); 809 284 810 int prepareExecute(uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 285 811 int clientConnect(uint32_t u32ClientID, void *pvClient); 286 812 int clientDisconnect(uint32_t u32ClientID, void *pvClient); 287 int assignHostCmdToGuest(const VBOXGUESTCTRLHOSTCMD *pCmd, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);288 int retrieveNextHostCmd(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);813 int clientGetCommand(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 814 int clientSetMsgFilter(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 289 815 int cancelHostCmd(uint32_t u32ContextID); 290 int cancelPendingWaits(uint32_t u32ClientID); 291 int notifyHost(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 292 int processHostCmd(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 293 void call(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, 294 void *pvClient, uint32_t eFunction, uint32_t cParms, 295 VBOXHGCMSVCPARM paParms[]); 816 int cancelPendingWaits(uint32_t u32ClientID, int rcPending); 817 int hostCallback(VBOXHGCMCALLHANDLE callHandle, uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 818 int hostProcessCommand(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 819 void call(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, void *pvClient, uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 296 820 int hostCall(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 297 int uninit( );821 int uninit(void); 298 822 }; 299 300 301 /**302 * Stores a HGCM request in an internal buffer. Needs to be free'd using paramBufferFree().303 *304 * @return IPRT status code.305 * @param pBuf Buffer to store the HGCM request into.306 * @param uMsg Message type.307 * @param cParms Number of parameters of HGCM request.308 * @param paParms Array of parameters of HGCM request.309 */310 int Service::paramBufferAllocate(PVBOXGUESTCTRPARAMBUFFER pBuf, uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])311 {312 AssertPtrReturn(pBuf, VERR_INVALID_POINTER);313 if (cParms)314 AssertPtrReturn(paParms, VERR_INVALID_POINTER);315 316 /* Paranoia. */317 if (cParms > 256)318 cParms = 256;319 320 int rc = VINF_SUCCESS;321 322 /*323 * Don't verify anything here (yet), because this function only buffers324 * the HGCM data into an internal structure and reaches it back to the guest (client)325 * in an unmodified state.326 */327 pBuf->uMsg = uMsg;328 pBuf->uParmCount = cParms;329 if (pBuf->uParmCount)330 {331 pBuf->pParms = (VBOXHGCMSVCPARM*)RTMemAlloc(sizeof(VBOXHGCMSVCPARM) * pBuf->uParmCount);332 if (NULL == pBuf->pParms)333 rc = VERR_NO_MEMORY;334 }335 336 if (RT_SUCCESS(rc))337 {338 for (uint32_t i = 0; i < pBuf->uParmCount; i++)339 {340 pBuf->pParms[i].type = paParms[i].type;341 switch (paParms[i].type)342 {343 case VBOX_HGCM_SVC_PARM_32BIT:344 pBuf->pParms[i].u.uint32 = paParms[i].u.uint32;345 break;346 347 case VBOX_HGCM_SVC_PARM_64BIT:348 /* Not supported yet. */349 break;350 351 case VBOX_HGCM_SVC_PARM_PTR:352 pBuf->pParms[i].u.pointer.size = paParms[i].u.pointer.size;353 if (pBuf->pParms[i].u.pointer.size > 0)354 {355 pBuf->pParms[i].u.pointer.addr = RTMemAlloc(pBuf->pParms[i].u.pointer.size);356 if (NULL == pBuf->pParms[i].u.pointer.addr)357 {358 rc = VERR_NO_MEMORY;359 break;360 }361 else362 memcpy(pBuf->pParms[i].u.pointer.addr,363 paParms[i].u.pointer.addr,364 pBuf->pParms[i].u.pointer.size);365 }366 else367 {368 /* Size is 0 -- make sure we don't have any pointer. */369 pBuf->pParms[i].u.pointer.addr = NULL;370 }371 break;372 373 default:374 break;375 }376 if (RT_FAILURE(rc))377 break;378 }379 }380 return rc;381 }382 383 /**384 * Frees a buffered HGCM request.385 *386 * @return IPRT status code.387 * @param pBuf Parameter buffer to free.388 */389 void Service::paramBufferFree(PVBOXGUESTCTRPARAMBUFFER pBuf)390 {391 AssertPtr(pBuf);392 for (uint32_t i = 0; i < pBuf->uParmCount; i++)393 {394 switch (pBuf->pParms[i].type)395 {396 case VBOX_HGCM_SVC_PARM_PTR:397 if (pBuf->pParms[i].u.pointer.size > 0)398 RTMemFree(pBuf->pParms[i].u.pointer.addr);399 break;400 }401 }402 if (pBuf->uParmCount)403 {404 RTMemFree(pBuf->pParms);405 pBuf->uParmCount = 0;406 }407 }408 409 /**410 * Copies data from a buffered HGCM request to the current HGCM request.411 *412 * @return IPRT status code.413 * @param paDstParms Array of parameters of HGCM request to fill the data into.414 * @param cPDstarms Number of parameters the HGCM request can handle.415 * @param pSrcBuf Parameter buffer to assign.416 */417 int Service::paramBufferAssign(VBOXHGCMSVCPARM paDstParms[], uint32_t cDstParms, const VBOXGUESTCTRPARAMBUFFER *pSrcBuf)418 {419 AssertPtr(pSrcBuf);420 int rc = VINF_SUCCESS;421 if (cDstParms != pSrcBuf->uParmCount)422 {423 LogFlowFunc(("Parameter count does not match (got %u, expected %u)\n",424 cDstParms, pSrcBuf->uParmCount));425 rc = VERR_INVALID_PARAMETER;426 }427 else428 {429 for (uint32_t i = 0; i < pSrcBuf->uParmCount; i++)430 {431 if (paDstParms[i].type != pSrcBuf->pParms[i].type)432 {433 LogFlowFunc(("Parameter %u type mismatch (got %u, expected %u)\n",434 i, paDstParms[i].type, pSrcBuf->pParms[i].type));435 rc = VERR_INVALID_PARAMETER;436 }437 else438 {439 switch (pSrcBuf->pParms[i].type)440 {441 case VBOX_HGCM_SVC_PARM_32BIT:442 paDstParms[i].u.uint32 = pSrcBuf->pParms[i].u.uint32;443 break;444 445 case VBOX_HGCM_SVC_PARM_PTR:446 {447 if (!pSrcBuf->pParms[i].u.pointer.size)448 continue; /* Only copy buffer if there actually is something to copy. */449 450 if (!paDstParms[i].u.pointer.addr)451 rc = VERR_INVALID_PARAMETER;452 453 if (paDstParms[i].u.pointer.size < pSrcBuf->pParms[i].u.pointer.size)454 rc = VERR_BUFFER_OVERFLOW;455 456 if (RT_SUCCESS(rc))457 {458 memcpy(paDstParms[i].u.pointer.addr,459 pSrcBuf->pParms[i].u.pointer.addr,460 pSrcBuf->pParms[i].u.pointer.size);461 }462 463 break;464 }465 466 case VBOX_HGCM_SVC_PARM_64BIT:467 /* Fall through is intentional. */468 default:469 LogFlowFunc(("Parameter %u of type %u is not supported yet\n",470 i, pSrcBuf->pParms[i].type));471 rc = VERR_NOT_SUPPORTED;472 break;473 }474 }475 476 if (RT_FAILURE(rc))477 {478 LogFlowFunc(("Parameter %u invalid (rc=%Rrc), refusing\n",479 i, rc));480 break;481 }482 }483 }484 return rc;485 }486 823 487 824 /** … … 494 831 int Service::clientConnect(uint32_t u32ClientID, void *pvClient) 495 832 { 496 LogFlowFunc(("New client (%ld) connected\n", u32ClientID)); 497 if (mNumClients < UINT32_MAX) 498 mNumClients++; 499 else 500 AssertMsgFailed(("Max. number of clients reached\n")); 833 LogFlowFunc(("New client with ID=%RU32 connected\n", u32ClientID)); 834 #ifdef VBOX_STRICT 835 ClientStateMapIterConst it = mClientStateMap.find(u32ClientID); 836 if (it != mClientStateMap.end()) 837 { 838 AssertMsgFailed(("Client with ID=%RU32 already connected when it should not\n", 839 u32ClientID)); 840 return VERR_ALREADY_EXISTS; 841 } 842 #endif 843 ClientState cs(mpHelpers); 844 mClientStateMap[u32ClientID] = cs; 845 /** @todo Exception handling! */ 501 846 return VINF_SUCCESS; 502 847 } … … 513 858 int Service::clientDisconnect(uint32_t u32ClientID, void *pvClient) 514 859 { 515 LogFlowFunc(("Client (ID=%u, %u clients total) disconnected\n", 516 u32ClientID, mNumClients)); 517 Assert(mNumClients > 0); 518 mNumClients--; 860 LogFlowFunc(("Client with ID=%RU32 (%zu clients total) disconnected\n", 861 u32ClientID, mClientStateMap.size())); 519 862 520 863 /* If this was the last connected (guest) client we need to 521 864 * unblock all eventually queued up (waiting) host calls. */ 522 bool fAllClientsDisconnected = m NumClients== 0;865 bool fAllClientsDisconnected = mClientStateMap.size() == 0; 523 866 if (fAllClientsDisconnected) 524 LogFlowFunc(("No connected clients left, notifying all queued up callbacks\n"));867 LogFlowFunc(("No connected clients left, notifying all queued up host callbacks\n")); 525 868 526 869 /* … … 529 872 int rc = VINF_SUCCESS; 530 873 531 CallListIter itCall = mClientWaiterList.begin(); 532 while (itCall != mClientWaiterList.end()) 533 { 534 if (itCall->mClientID == u32ClientID) 535 { 536 itCall = mClientWaiterList.erase(itCall); 537 } 538 else 539 itCall++; 540 } 541 542 ClientContextsListIter itContextList = mClientContextsList.begin(); 543 while ( itContextList != mClientContextsList.end() 874 ClientStateMapIter itClientState = mClientStateMap.begin(); 875 while ( itClientState != mClientStateMap.end() 544 876 && RT_SUCCESS(rc)) 545 877 { … … 549 881 * anymore. 550 882 */ 551 if ( itC ontextList->mClientID== u32ClientID883 if ( itClientState->first == u32ClientID 552 884 || fAllClientsDisconnected) 553 885 { 554 std::list< uint32_t >::iterator itContext = itContextList->mContextList.begin(); 555 while (itContext != itContextList->mContextList.end()) 886 LogFlowFunc(("Cancelling %RU32 context of client ID=%RU32\n", 887 itClientState->second.mContextMap.size(), u32ClientID)); 888 889 ClientContextMapIter itContext = itClientState->second.mContextMap.begin(); 890 while (itContext != itClientState->second.mContextMap.end()) 556 891 { 557 uint32_t uContextID = (*itContext);892 uint32_t uContextID = itContext->first; 558 893 559 894 /* … … 561 896 * around and need to be cleaned up (canceling waits etc). 562 897 */ 563 LogFlowFunc(("Notifying CID=% uof disconnect ...\n", uContextID));564 rc= cancelHostCmd(uContextID);898 LogFlowFunc(("Notifying CID=%RU32 of disconnect ...\n", uContextID)); 899 int rc2 = cancelHostCmd(uContextID); 565 900 if (RT_FAILURE(rc)) 566 901 { 567 LogFlowFunc(("Cancelling of CID=%ufailed with rc=%Rrc\n",568 uContextID, rc ));902 LogFlowFunc(("Cancelling assigned client CID=%RU32 failed with rc=%Rrc\n", 903 uContextID, rc2)); 569 904 /* Keep going. */ 570 905 } 571 906 907 AssertPtr(itContext->second.mpHostCmd); 908 itContext->second.mpHostCmd->Release(); 909 910 LogFlowFunc(("Released host command CID=%RU32 returned with rc=%Rrc\n", 911 uContextID, rc2)); 912 572 913 itContext++; 573 914 } 574 itC ontextList = mClientContextsList.erase(itContextList);915 itClientState = mClientStateMap.erase(itClientState); 575 916 } 576 917 else 577 itC ontextList++;918 itClientState++; 578 919 } 579 920 … … 585 926 * via a (multi stage) progress object. 586 927 */ 587 HostCmdListIter itHostCmd; 588 for (itHostCmd = mHostCmds.begin(); itHostCmd != mHostCmds.end(); itHostCmd++) 589 { 590 rc = cancelHostCmd(itHostCmd->mContextID); 591 if (RT_FAILURE(rc)) 928 HostCommand *pCurCmd = RTListGetFirst(&mHostCmdList, HostCommand, Node); 929 while (pCurCmd) 930 { 931 HostCommand *pNext = RTListNodeGetNext(&pCurCmd->Node, HostCommand, Node); 932 bool fLast = RTListNodeIsLast(&mHostCmdList, &pCurCmd->Node); 933 934 int rc2 = cancelHostCmd(pCurCmd->mContextID); 935 if (RT_FAILURE(rc2)) 592 936 { 593 LogFlowFunc(("Cancelling of buffered CID=%ufailed with rc=%Rrc\n",594 itHostCmd->mContextID, rc));937 LogFlowFunc(("Cancelling host command with CID=%u (refCount=%RU32) failed with rc=%Rrc\n", 938 pCurCmd->mContextID, pCurCmd->mRefCount, rc2)); 595 939 /* Keep going. */ 596 940 } 597 941 598 paramBufferFree(&itHostCmd->mParmBuf); 599 } 600 601 mHostCmds.clear(); 602 } 603 604 return rc; 605 } 606 607 /** 608 * Assigns a specified host command to a client. 609 * 610 * @return IPRT status code. 611 * @param pCmd Host command to send. 612 * @param callHandle Call handle of the client to send the command to. 613 * @param cParms Number of parameters. 614 * @param paParms Array of parameters. 615 */ 616 int Service::assignHostCmdToGuest(const VBOXGUESTCTRLHOSTCMD *pCmd, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 617 { 618 AssertPtrReturn(pCmd, VERR_INVALID_POINTER); 619 int rc; 620 621 /* Does the current host command need more parameter space which 622 * the client does not provide yet? */ 623 if (pCmd->mParmBuf.uParmCount > cParms) 624 { 625 paParms[0].setUInt32(pCmd->mParmBuf.uMsg); /* Message ID */ 626 paParms[1].setUInt32(pCmd->mParmBuf.uParmCount); /* Required parameters for message */ 627 628 /* 629 * So this call apparently failed because the guest wanted to peek 630 * how much parameters it has to supply in order to successfully retrieve 631 * this command. Let's tell him so! 632 */ 633 rc = VERR_TOO_MUCH_DATA; 634 } 635 else 636 { 637 rc = paramBufferAssign(paParms, cParms, &pCmd->mParmBuf); 638 639 /* Has there been enough parameter space but the wrong parameter types 640 * were submitted -- maybe the client was just asking for the next upcoming 641 * host message? 642 * 643 * Note: To keep this compatible to older clients we return VERR_TOO_MUCH_DATA 644 * in every case. */ 645 if (RT_FAILURE(rc)) 646 rc = VERR_TOO_MUCH_DATA; 647 } 648 649 LogFlowFunc(("Returned with rc=%Rrc\n", rc)); 942 pCurCmd->Free(); 943 944 RTListNodeRemove(&pCurCmd->Node); 945 RTMemFree(pCurCmd); 946 947 if (fLast) 948 break; 949 950 pCurCmd = pNext; 951 } 952 953 Assert(RTListIsEmpty(&mHostCmdList)); 954 } 955 650 956 return rc; 651 957 } … … 661 967 * @param paParms Array of parameters. 662 968 */ 663 int Service::retrieveNextHostCmd(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, 664 uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 665 { 666 int rc = VINF_SUCCESS; 667 969 int Service::clientGetCommand(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, 970 uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 971 { 668 972 /* 669 973 * Lookup client in our list so that we can assign the context ID of 670 974 * a command to that client. 671 975 */ 672 std::list< ClientContexts >::reverse_iterator it = mClientContextsList.rbegin(); 673 while (it != mClientContextsList.rend()) 674 { 675 if (it->mClientID == u32ClientID) 676 break; 677 it++; 678 } 679 680 /* Not found? Add client to list. */ 681 if (it == mClientContextsList.rend()) 682 { 683 mClientContextsList.push_back(ClientContexts(u32ClientID)); 684 it = mClientContextsList.rbegin(); 685 } 686 Assert(it != mClientContextsList.rend()); 976 ClientStateMapIter itClientState = mClientStateMap.find(u32ClientID); 977 AssertMsg(itClientState != mClientStateMap.end(), ("Client with ID=%RU32 not found when it should be present\n", 978 u32ClientID)); 979 if (itClientState == mClientStateMap.end()) 980 return VERR_NOT_FOUND; /* Should never happen. */ 981 982 ClientState &clientState = itClientState->second; 983 984 /* Use the current (inbound) connection. */ 985 ClientConnection thisCon; 986 thisCon.mHandle = callHandle; 987 thisCon.mNumParms = cParms; 988 thisCon.mParms = paParms; 687 989 688 990 /* 689 991 * If host command list is empty (nothing to do right now) just 690 992 * defer the call until we got something to do (makes the client 691 * wait , depending on the flags set).692 */ 693 i f (mHostCmds.empty()) /* If command list is empty, defer ... */694 {695 mClientWaiterList.push_back(ClientWaiter(u32ClientID, callHandle, paParms, cParms));696 rc = VINF_HGCM_ASYNC_EXECUTE;993 * wait). 994 */ 995 int rc; 996 if (RTListIsEmpty(&mHostCmdList)) 997 { 998 rc = clientState.SetPending(&thisCon); 697 999 } 698 1000 else 699 1001 { 700 /* 701 * Get the next unassigned host command in the list. 702 */ 703 VBOXGUESTCTRLHOSTCMD &curCmd = mHostCmds.front(); 704 rc = assignHostCmdToGuest(&curCmd, callHandle, cParms, paParms); 705 if (RT_SUCCESS(rc)) 706 { 707 /* Remember which client processes which context (for 708 * later reference & cleanup). */ 709 /// @todo r=bird: check if already in the list. 710 /// @todo Use a map instead of a list? 711 it->mContextList.push_back(curCmd.mContextID); 712 713 /* Only if the guest really got and understood the message remove it from the list. */ 714 paramBufferFree(&curCmd.mParmBuf); 715 mHostCmds.pop_front(); 716 } 717 else 718 { 719 bool fRemoveCmd = false; 720 uint32_t uTries = curCmd.mTries++; 721 722 /* If the client understood the message but supplied too little buffer space 723 * don't send this message again and drop it after 3 unsuccessful attempts. 724 * The host then should take care of next actions (maybe retry it with a smaller buffer). */ 725 if ( rc == VERR_BUFFER_OVERFLOW 726 && uTries >= 3) 727 { 728 fRemoveCmd = true; 729 } 730 /* Client did not understand the message or something else weird happened. Try again one 731 * more time and drop it if it didn't get handled then. */ 732 else if (uTries > 1) 733 fRemoveCmd = true; 734 735 if (fRemoveCmd) 736 { 737 paramBufferFree(&curCmd.mParmBuf); 738 mHostCmds.pop_front(); 739 } 740 } 741 } 1002 rc = clientState.RunNow(&thisCon, &mHostCmdList); 1003 } 1004 1005 LogFlowFunc(("Returned with rc=%Rrc\n", rc)); 742 1006 return rc; 743 1007 } 744 1008 745 /** 746 * Cancels a buffered host command to unblock waits on Main side 747 * (via (multi stage) progress objects. 1009 int Service::clientSetMsgFilter(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, 1010 uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 1011 { 1012 /* 1013 * Lookup client in our list so that we can assign the context ID of 1014 * a command to that client. 1015 */ 1016 ClientStateMapIter itClientState = mClientStateMap.find(u32ClientID); 1017 AssertMsg(itClientState != mClientStateMap.end(), ("Client with ID=%RU32 not found when it should be present\n", 1018 u32ClientID)); 1019 if (itClientState == mClientStateMap.end()) 1020 return VERR_NOT_FOUND; /* Should never happen. */ 1021 1022 if (cParms != 2) 1023 return VERR_INVALID_PARAMETER; 1024 1025 uint32_t uMaskAdd; 1026 int rc = paParms[0].getUInt32(&uMaskAdd); 1027 if (RT_SUCCESS(rc)) 1028 { 1029 /* paParms[1] unused yet. */ 1030 1031 ClientState &clientState = itClientState->second; 1032 1033 clientState.mFlags |= CLIENTSTATE_FLAG_CONTEXTFILTER; 1034 clientState.mContextFilter = uMaskAdd; 1035 1036 LogFlowFunc(("Client ID=%RU32 now has filter=%x enabled (flags=%x)\n", 1037 u32ClientID, clientState.mContextFilter, clientState.mFlags)); 1038 } 1039 1040 LogFlowFunc(("Returned with rc=%Rrc\n", rc)); 1041 return rc; 1042 } 1043 1044 /** 1045 * Cancels a buffered host command to unblock waiting on Main side 1046 * via callbacks. 748 1047 * 749 1048 * @return IPRT status code. … … 756 1055 LogFlowFunc(("Cancelling CID=%u ...\n", u32ContextID)); 757 1056 758 CALLBACKDATACLIENTDISCONNECTED data; 759 data.hdr.u32Magic = CALLBACKDATAMAGIC_CLIENT_DISCONNECTED; 760 data.hdr.u32ContextID = u32ContextID; 1057 CALLBACKDATA_CLIENT_DISCONNECTED data; 1058 data.hdr.uContextID = u32ContextID; 761 1059 762 1060 AssertPtr(mpfnHostCallback); … … 772 1070 * @return IPRT status code. 773 1071 * @param u32ClientID The client's ID. 774 */ 775 int Service::cancelPendingWaits(uint32_t u32ClientID) 776 { 777 int rc = VINF_SUCCESS; 778 CallListIter it = mClientWaiterList.begin(); 779 while (it != mClientWaiterList.end()) 780 { 781 if (it->mClientID == u32ClientID) 782 { 783 if (it->mNumParms >= 2) 784 { 785 it->mParms[0].setUInt32(HOST_CANCEL_PENDING_WAITS); /* Message ID. */ 786 it->mParms[1].setUInt32(0); /* Required parameters for message. */ 787 } 788 if (mpHelpers) 789 mpHelpers->pfnCallComplete(it->mHandle, rc); 790 it = mClientWaiterList.erase(it); 791 } 792 else 793 it++; 794 } 795 return rc; 1072 * @param rcPending Result code for completing pending operation. 1073 */ 1074 int Service::cancelPendingWaits(uint32_t u32ClientID, int rcPending) 1075 { 1076 ClientStateMapIter itClientState = mClientStateMap.find(u32ClientID); 1077 if (itClientState != mClientStateMap.end()) 1078 return itClientState->second.CancelWaiting(rcPending); 1079 1080 return VINF_SUCCESS; 796 1081 } 797 1082 … … 801 1086 * 802 1087 * @return IPRT status code. 1088 * @param callHandle Call handle. 803 1089 * @param eFunction Function (event) that occured. 804 1090 * @param cParms Number of parameters. 805 1091 * @param paParms Array of parameters. 806 1092 */ 807 int Service::notifyHost(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 1093 int Service::hostCallback(VBOXHGCMCALLHANDLE callHandle, 1094 uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 808 1095 { 809 1096 LogFlowFunc(("eFunction=%ld, cParms=%ld, paParms=%p\n", 810 1097 eFunction, cParms, paParms)); 811 int rc = VINF_SUCCESS; 812 if ( eFunction == GUEST_EXEC_SEND_STATUS 813 && cParms == 5) 814 { 815 CALLBACKDATAEXECSTATUS data; 816 data.hdr.u32Magic = CALLBACKDATAMAGIC_EXEC_STATUS; 817 paParms[0].getUInt32(&data.hdr.u32ContextID); 818 819 paParms[1].getUInt32(&data.u32PID); 820 paParms[2].getUInt32(&data.u32Status); 821 paParms[3].getUInt32(&data.u32Flags); 822 paParms[4].getPointer(&data.pvData, &data.cbData); 823 824 if (mpfnHostCallback) 825 rc = mpfnHostCallback(mpvHostData, eFunction, 826 (void *)(&data), sizeof(data)); 827 } 828 else if ( eFunction == GUEST_EXEC_SEND_OUTPUT 829 && cParms == 5) 830 { 831 CALLBACKDATAEXECOUT data; 832 data.hdr.u32Magic = CALLBACKDATAMAGIC_EXEC_OUT; 833 paParms[0].getUInt32(&data.hdr.u32ContextID); 834 835 paParms[1].getUInt32(&data.u32PID); 836 paParms[2].getUInt32(&data.u32HandleId); 837 paParms[3].getUInt32(&data.u32Flags); 838 paParms[4].getPointer(&data.pvData, &data.cbData); 839 840 if (mpfnHostCallback) 841 rc = mpfnHostCallback(mpvHostData, eFunction, 842 (void *)(&data), sizeof(data)); 843 } 844 else if ( eFunction == GUEST_EXEC_SEND_INPUT_STATUS 845 && cParms == 5) 846 { 847 CALLBACKDATAEXECINSTATUS data; 848 data.hdr.u32Magic = CALLBACKDATAMAGIC_EXEC_IN_STATUS; 849 paParms[0].getUInt32(&data.hdr.u32ContextID); 850 851 paParms[1].getUInt32(&data.u32PID); 852 paParms[2].getUInt32(&data.u32Status); 853 paParms[3].getUInt32(&data.u32Flags); 854 paParms[4].getUInt32(&data.cbProcessed); 855 856 if (mpfnHostCallback) 857 rc = mpfnHostCallback(mpvHostData, eFunction, 858 (void *)(&data), sizeof(data)); 1098 1099 int rc; 1100 if (mpfnHostCallback) 1101 { 1102 VBOXGUESTCTRLHOSTCALLBACK data(cParms, paParms); 1103 rc = mpfnHostCallback(mpvHostData, eFunction, 1104 (void *)(&data), sizeof(data)); 859 1105 } 860 1106 else 861 1107 rc = VERR_NOT_SUPPORTED; 862 LogFlowFunc(("returning %Rrc\n", rc)); 1108 1109 LogFlowFunc(("Returning rc=%Rrc\n", rc)); 863 1110 return rc; 864 1111 } … … 873 1120 * @param paParms Array of parameters. 874 1121 */ 875 int Service:: processHostCmd(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[])1122 int Service::hostProcessCommand(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 876 1123 { 877 1124 /* … … 881 1128 * the guest is not running/system is messed up somehow. 882 1129 */ 883 if (m NumClients== 0)1130 if (mClientStateMap.size() == 0) 884 1131 return VERR_NOT_FOUND; 885 VBOXGUESTCTRLHOSTCMD newCmd; 886 int rc = paramBufferAllocate(&newCmd.mParmBuf, eFunction, cParms, paParms); 887 if ( RT_SUCCESS(rc) 888 && cParms) /* Make sure we at least get one parameter (that is, the context ID). */ 889 { 1132 1133 int rc; 1134 HostCommand *pHostCmd = (HostCommand*)RTMemAllocZ(sizeof(HostCommand)); 1135 if (pHostCmd) 1136 { 1137 rc = pHostCmd->Allocate(eFunction, cParms, paParms); 1138 if (RT_SUCCESS(rc)) 1139 RTListAppend(&mHostCmdList, &pHostCmd->Node); 1140 } 1141 else 1142 rc = VERR_NO_MEMORY; 1143 1144 if (RT_SUCCESS(rc)) 1145 { 1146 LogFlowFunc(("Handling host command CID=%RU32, numClients=%zu\n", 1147 pHostCmd->mContextID, mClientStateMap.size())); 1148 890 1149 /* 891 * Assume that the context ID *always* is the first parameter,892 * assign the context ID to thecommand.1150 * Wake up all pending clients which are interested in this 1151 * host command. 893 1152 */ 894 newCmd.mParmBuf.pParms[0].getUInt32(&newCmd.mContextID); 895 } 896 else if (!cParms) 897 rc = VERR_INVALID_PARAMETER; 898 899 if (RT_SUCCESS(rc)) 900 { 901 LogFlowFunc(("Handling host command CID = %u\n", 902 newCmd.mContextID)); 903 904 bool fProcessed = false; 905 906 /* Can we wake up a waiting client on guest? */ 907 if (!mClientWaiterList.empty()) 908 { 909 ClientWaiter guest = mClientWaiterList.front(); 910 rc = assignHostCmdToGuest(&newCmd, 911 guest.mHandle, guest.mNumParms, guest.mParms); 912 913 /* In any case the client did something, so wake up and remove from list. */ 914 AssertPtr(mpHelpers); 915 mpHelpers->pfnCallComplete(guest.mHandle, rc); 916 mClientWaiterList.pop_front(); 917 918 /* 919 * If we got back an error (like VERR_TOO_MUCH_DATA or VERR_BUFFER_OVERFLOW) 920 * we buffer the host command in the next block and return success to the host. 921 */ 922 if (RT_FAILURE(rc)) 1153 #ifdef DEBUG 1154 uint32_t uClientsWokenUp = 0; 1155 #endif 1156 1157 ClientStateMapIter itClientState = mClientStateMap.begin(); 1158 AssertMsg(itClientState != mClientStateMap.end(), ("Client state map is empty when it should not\n")); 1159 while (itClientState != mClientStateMap.end()) 1160 { 1161 if (itClientState->second.mIsPending) /* Only wake up pending clients. */ 923 1162 { 924 rc = VINF_SUCCESS; 925 } 926 else /* If command was understood by the client, free and remove from host commands list. */ 927 { 928 LogFlowFunc(("Host command CID = %u processed with rc=%Rrc\n", 929 newCmd.mContextID, rc)); 930 931 paramBufferFree(&newCmd.mParmBuf); 932 } 933 } 934 935 if (!fProcessed) 936 { 937 LogFlowFunc(("Buffering host command CID = %u (rc=%Rrc)\n", 938 newCmd.mContextID, rc)); 939 940 mHostCmds.push_back(newCmd); 941 } 1163 LogFlowFunc(("Waking up client ID=%RU32 (isPending=%RTbool) ...\n", 1164 itClientState->first, itClientState->second.mIsPending)); 1165 1166 ClientState &clientState = itClientState->second; 1167 int rc2 = clientState.Wakeup(&mHostCmdList); 1168 LogFlowFunc(("Client ID=%RU32 wakeup ended with rc=%Rrc\n", 1169 itClientState->first, rc2)); 1170 #ifdef DEBUG 1171 uClientsWokenUp++; 1172 #endif 1173 } 1174 else 1175 LogFlowFunc(("Client ID=%RU32 is not in pending state\n", 1176 itClientState->first)); 1177 1178 itClientState++; 1179 } 1180 1181 #ifdef DEBUG 1182 LogFlowFunc(("%RU32 clients have been succcessfully woken up\n", 1183 uClientsWokenUp)); 1184 #endif 942 1185 } 943 1186 … … 960 1203 { 961 1204 int rc = VINF_SUCCESS; 962 LogFlowFunc(("u32ClientID = %u, fn = %u, cParms = %u, paParms =0x%p\n",1205 LogFlowFunc(("u32ClientID=%RU32, fn=%RU32, cParms=%RU32, paParms=0x%p\n", 963 1206 u32ClientID, eFunction, cParms, paParms)); 964 1207 try 965 1208 { 966 switch (eFunction) 967 { 968 /* 969 * The guest asks the host for the next message to process. 970 */ 971 case GUEST_GET_HOST_MSG: 972 LogFlowFunc(("GUEST_GET_HOST_MSG\n")); 973 rc = retrieveNextHostCmd(u32ClientID, callHandle, cParms, paParms); 974 break; 975 976 /* 977 * The guest wants to shut down and asks us (this service) to cancel 978 * all blocking pending waits (VINF_HGCM_ASYNC_EXECUTE) so that the 979 * guest can gracefully shut down. 980 */ 981 case GUEST_CANCEL_PENDING_WAITS: 982 LogFlowFunc(("GUEST_CANCEL_PENDING_WAITS\n")); 983 rc = cancelPendingWaits(u32ClientID); 984 break; 985 986 /* 987 * For all other regular commands we call our notifyHost 988 * function. If the current command does not support notifications 989 * notifyHost will return VERR_NOT_SUPPORTED. 990 */ 991 default: 992 rc = notifyHost(eFunction, cParms, paParms); 993 break; 994 } 995 if (rc != VINF_HGCM_ASYNC_EXECUTE) 996 { 997 /* Tell the client that the call is complete (unblocks waiting). */ 998 AssertPtr(mpHelpers); 999 mpHelpers->pfnCallComplete(callHandle, rc); 1209 /* 1210 * The guest asks the host for the next message to process. 1211 */ 1212 if (eFunction == GUEST_MSG_WAIT) 1213 { 1214 LogFlowFunc(("GUEST_MSG_GET\n")); 1215 rc = clientGetCommand(u32ClientID, callHandle, cParms, paParms); 1216 } 1217 else 1218 { 1219 switch (eFunction) 1220 { 1221 /* 1222 * A client wants to shut down and asks us (this service) to cancel 1223 * all blocking/pending waits (VINF_HGCM_ASYNC_EXECUTE) so that the 1224 * client can gracefully shut down. 1225 */ 1226 case GUEST_CANCEL_PENDING_WAITS: 1227 LogFlowFunc(("GUEST_CANCEL_PENDING_WAITS\n")); 1228 rc = cancelPendingWaits(u32ClientID, VINF_SUCCESS /* Pending result */); 1229 break; 1230 1231 /* 1232 * The guest only wants certain messages set by the filter mask(s). 1233 * Since VBox 4.3+. 1234 */ 1235 case GUEST_MSG_FILTER: 1236 LogFlowFunc(("GUEST_MSG_FILTER\n")); 1237 rc = clientSetMsgFilter(u32ClientID, callHandle, cParms, paParms); 1238 break; 1239 1240 /* 1241 * For all other regular commands we call our hostCallback 1242 * function. If the current command does not support notifications, 1243 * notifyHost will return VERR_NOT_SUPPORTED. 1244 */ 1245 default: 1246 rc = hostCallback(callHandle, eFunction, cParms, paParms); 1247 break; 1248 } 1249 1250 if (rc != VINF_HGCM_ASYNC_EXECUTE) 1251 { 1252 /* Tell the client that the call is complete (unblocks waiting). */ 1253 AssertPtr(mpHelpers); 1254 mpHelpers->pfnCallComplete(callHandle, rc); 1255 } 1000 1256 } 1001 1257 } … … 1004 1260 rc = VERR_NO_MEMORY; 1005 1261 } 1006 LogFlowFunc(("rc = %Rrc\n", rc));1007 1262 } 1008 1263 … … 1015 1270 { 1016 1271 int rc = VERR_NOT_SUPPORTED; 1017 LogFlowFunc(("fn = %u, cParms = %u, paParms =0x%p\n",1272 LogFlowFunc(("fn=%RU32, cParms=%RU32, paParms=0x%p\n", 1018 1273 eFunction, cParms, paParms)); 1019 1274 try 1020 1275 { 1021 rc = processHostCmd(eFunction, cParms, paParms); 1276 switch (eFunction) 1277 { 1278 /** 1279 * Host 1280 */ 1281 case HOST_CANCEL_PENDING_WAITS: 1282 { 1283 LogFlowFunc(("HOST_CANCEL_PENDING_WAITS\n")); 1284 ClientStateMapIter itClientState = mClientStateMap.begin(); 1285 while (itClientState != mClientStateMap.end()) 1286 { 1287 int rc2 = itClientState->second.CancelWaiting(VINF_SUCCESS /* Pending rc. */); 1288 if (RT_FAILURE(rc2)) 1289 LogFlowFunc(("Cancelling waiting for client ID=%RU32 failed with rc=%Rrc", 1290 itClientState->first, rc2)); 1291 itClientState++; 1292 } 1293 rc = VINF_SUCCESS; 1294 break; 1295 } 1296 1297 default: 1298 rc = hostProcessCommand(eFunction, cParms, paParms); 1299 break; 1300 } 1022 1301 } 1023 1302 catch (std::bad_alloc) … … 1026 1305 } 1027 1306 1028 LogFlowFunc(("rc = %Rrc\n", rc));1029 1307 return rc; 1030 1308 } … … 1032 1310 int Service::uninit() 1033 1311 { 1034 Assert( mHostCmds.empty());1312 Assert(RTListIsEmpty(&mHostCmdList)); 1035 1313 1036 1314 return VINF_SUCCESS; -
trunk/src/VBox/HostServices/GuestControl/testcase/tstGuestControlSvc.cpp
r36873 r44863 6 6 7 7 /* 8 * Copyright (C) 2011 Oracle Corporation8 * Copyright (C) 2011-2013 Oracle Corporation 9 9 * 10 10 * This file is part of VirtualBox Open Source Edition (OSE), as … … 157 157 static CMDHOST s_aCmdHostAll[] = 158 158 { 159 /** No client connected, invalid command. */ 160 { 1024 /* Not existing command */, 0, 0, false, VERR_NOT_SUPPORTED }, 161 { -1 /* Invalid command */, 0, 0, false, VERR_NOT_SUPPORTED }, 159 #if 0 160 /** No client connected. */ 161 { 1024 /* Not existing command */, 0, 0, false, VERR_NOT_FOUND }, 162 { -1 /* Invalid command */, 0, 0, false, VERR_NOT_FOUND }, 162 163 { HOST_CANCEL_PENDING_WAITS, 1024, 0, false, VERR_NOT_FOUND }, 163 164 { HOST_CANCEL_PENDING_WAITS, 0, &s_aParms[0], false, VERR_NOT_FOUND }, … … 166 167 { HOST_CANCEL_PENDING_WAITS, 0, 0, false, VERR_NOT_FOUND }, 167 168 168 /** Client connected. */ 169 { 1024 /* Not existing command */, 0, 0, true, VERR_NOT_SUPPORTED }, 170 { -1 /* Invalid command */, 0, 0, true, VERR_NOT_SUPPORTED }, 169 /** Client connected, no parameters given. */ 170 { HOST_EXEC_SET_INPUT, 0 /* No parameters given */, 0, true, VERR_INVALID_PARAMETER }, 171 { 1024 /* Not existing command */, 0 /* No parameters given */, 0, true, VERR_INVALID_PARAMETER }, 172 { -1 /* Invalid command */, 0 /* No parameters given */, 0, true, VERR_INVALID_PARAMETER }, 171 173 172 174 /** Client connected, valid parameters given. */ … … 174 176 { HOST_CANCEL_PENDING_WAITS, 1024, &s_aParms[0], true, VINF_SUCCESS }, 175 177 { HOST_CANCEL_PENDING_WAITS, 0, &s_aParms[0], true, VINF_SUCCESS}, 178 #endif 176 179 177 180 /** Client connected, invalid parameters given. */ 178 { HOST_ CANCEL_PENDING_WAITS, 1024, 0, true, VERR_INVALID_POINTER },179 { HOST_ CANCEL_PENDING_WAITS, 1, 0, true, VERR_INVALID_POINTER },180 { HOST_ CANCEL_PENDING_WAITS, -1, 0, true, VERR_INVALID_POINTER },181 { HOST_EXEC_CMD, 1024, 0, true, VERR_INVALID_POINTER }, 182 { HOST_EXEC_CMD, 1, 0, true, VERR_INVALID_POINTER }, 183 { HOST_EXEC_CMD, -1, 0, true, VERR_INVALID_POINTER }, 181 184 182 185 /** Client connected, parameters given. */ … … 184 187 { HOST_EXEC_CMD, 1, &s_aParms[0], true, VINF_SUCCESS }, 185 188 { HOST_EXEC_SET_INPUT, 1, &s_aParms[0], true, VINF_SUCCESS }, 186 { HOST_EXEC_GET_OUTPUT, 1, &s_aParms[0], true, VINF_SUCCESS } 189 { HOST_EXEC_GET_OUTPUT, 1, &s_aParms[0], true, VINF_SUCCESS }, 190 191 /** Client connected, unknown command + valid parameters given. */ 192 { -1, 1, &s_aParms[0], true, VINF_SUCCESS } 187 193 }; 188 194 … … 203 209 /* No commands from host yet. */ 204 210 static VBOXHGCMSVCPARM s_aParmsGuest[8]; 211 s_aParmsGuest[0].setUInt32(0 /* Msg type */); 212 s_aParmsGuest[1].setUInt32(0 /* Parameters */); 205 213 pTable->pfnCall(pTable->pvService, &callHandle, 1 /* Client ID */, NULL /* pvClient */, 206 GUEST_ GET_HOST_MSG, 2, &s_aParmsGuest[0]);214 GUEST_MSG_WAIT, 2, &s_aParmsGuest[0]); 207 215 RTTEST_CHECK_RC_RET(g_hTest, callHandle.rc, VINF_SUCCESS, callHandle.rc); 208 216 … … 211 219 s_aParmsHost[0].setUInt32(1000 /* Context ID */); 212 220 s_aParmsHost[1].setString("foo.bar"); 213 214 rc = pTable->pfnHostCall(pTable->pvService, HOST_EXEC_CMD, 2, &s_aParmsHost[0]); 221 s_aParmsHost[2].setString("baz"); 222 223 rc = pTable->pfnHostCall(pTable->pvService, HOST_EXEC_CMD, 3, &s_aParmsHost[0]); 215 224 RTTEST_CHECK_RC_RET(g_hTest, rc, VINF_SUCCESS, rc); 216 217 /* Client: Get host command with a invalid parameter count specified. */218 pTable->pfnCall(pTable->pvService, &callHandle, 1 /* Client ID */, NULL /* pvClient */,219 GUEST_GET_HOST_MSG, 1024, &s_aParmsGuest[0]);220 RTTEST_CHECK_RC_RET(g_hTest, callHandle.rc, VERR_INVALID_PARAMETER, callHandle.rc);221 pTable->pfnCall(pTable->pvService, &callHandle, 1 /* Client ID */, NULL /* pvClient */,222 GUEST_GET_HOST_MSG, -1, &s_aParmsGuest[0]);223 RTTEST_CHECK_RC_RET(g_hTest, callHandle.rc, VERR_INVALID_PARAMETER, callHandle.rc);224 pTable->pfnCall(pTable->pvService, &callHandle, 1 /* Client ID */, NULL /* pvClient */,225 GUEST_GET_HOST_MSG, -1, NULL);226 RTTEST_CHECK_RC_RET(g_hTest, callHandle.rc, VERR_INVALID_PARAMETER, callHandle.rc);227 pTable->pfnCall(pTable->pvService, &callHandle, 1 /* Client ID */, NULL /* pvClient */,228 GUEST_GET_HOST_MSG, 16, NULL);229 RTTEST_CHECK_RC_RET(g_hTest, callHandle.rc, VERR_INVALID_PARAMETER, callHandle.rc);230 231 /* Client: Get host command with a too small HGCM array. */232 pTable->pfnCall(pTable->pvService, &callHandle, 1 /* Client ID */, NULL /* pvClient */,233 GUEST_GET_HOST_MSG, 0, &s_aParmsGuest[0]);234 RTTEST_CHECK_RC_RET(g_hTest, callHandle.rc, VERR_TOO_MUCH_DATA, callHandle.rc);235 pTable->pfnCall(pTable->pvService, &callHandle, 1 /* Client ID */, NULL /* pvClient */,236 GUEST_GET_HOST_MSG, 1, &s_aParmsGuest[0]);237 RTTEST_CHECK_RC_RET(g_hTest, callHandle.rc, VERR_TOO_MUCH_DATA, callHandle.rc);238 239 /* Client: Get host command without an allocated buffer. */240 pTable->pfnCall(pTable->pvService, &callHandle, 1 /* Client ID */, NULL /* pvClient */,241 GUEST_GET_HOST_MSG, 2, &s_aParmsGuest[0]);242 RTTEST_CHECK_RC_RET(g_hTest, callHandle.rc, VERR_BUFFER_OVERFLOW, callHandle.rc);243 244 /* Client: Get host command, this time with a valid buffer. */245 char szBuf[16];246 s_aParmsGuest[1].setPointer(szBuf, sizeof(szBuf));247 pTable->pfnCall(pTable->pvService, &callHandle, 1 /* Client ID */, NULL /* pvClient */,248 GUEST_GET_HOST_MSG, 2, &s_aParmsGuest[0]);249 RTTEST_CHECK_RC_RET(g_hTest, callHandle.rc, VINF_SUCCESS, callHandle.rc);250 251 /* Client: Now make sure there's no host message left anymore. */252 pTable->pfnCall(pTable->pvService, &callHandle, 1 /* Client ID */, NULL /* pvClient */,253 GUEST_GET_HOST_MSG, 2, &s_aParmsGuest[0]);254 RTTEST_CHECK_RC_RET(g_hTest, callHandle.rc, VINF_SUCCESS, callHandle.rc);255 225 256 226 /* Client: Disconnect again. */
Note:
See TracChangeset
for help on using the changeset viewer.