Changeset 75798 in vbox
- Timestamp:
- Nov 28, 2018 11:47:11 PM (6 years ago)
- Location:
- trunk
- Files:
-
- 10 edited
-
include/VBox/HostServices/GuestControlSvc.h (modified) (9 diffs)
-
include/VBox/VBoxGuestLib.h (modified) (1 diff)
-
src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibGuestCtrl.cpp (modified) (3 diffs)
-
src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp (modified) (1 diff)
-
src/VBox/Additions/common/VBoxService/VBoxServiceControlSession.cpp (modified) (2 diffs)
-
src/VBox/HostServices/GuestControl/service.cpp (modified) (43 diffs)
-
src/VBox/Main/include/GuestSessionImpl.h (modified) (1 diff)
-
src/VBox/Main/src-client/GuestCtrlPrivate.cpp (modified) (2 diffs)
-
src/VBox/Main/src-client/GuestSessionImpl.cpp (modified) (4 diffs)
-
src/VBox/Main/src-client/HGCMThread.cpp (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/HostServices/GuestControlSvc.h
r75757 r75798 109 109 } VBOXGUESTCTRLHOSTCALLBACK, *PVBOXGUESTCTRLHOSTCALLBACK; 110 110 111 112 /** @name Host message destiation flags. 113 * 114 * This is ORed into the context ID parameter Main after extending it to 64-bit. 115 * 116 * @internal Host internal. 117 * @{ */ 118 #define VBOX_GUESTCTRL_DST_ROOT_SVC RT_BIT_64(63) 119 #define VBOX_GUESTCTRL_DST_SESSION RT_BIT_64(62) 120 #define VBOX_GUESTCTRL_DST_BOTH ( VBOX_GUESTCTRL_DST_ROOT_SVC | VBOX_GUESTCTRL_DST_SESSION ) 121 /** @} */ 122 123 111 124 /** 112 125 * The service functions which are callable by host. … … 204 217 }; 205 218 219 220 /** 221 * Translates a guest control host function function enum to at string. 222 * @returns Enum string name. 223 * @param enmFunction The function name to translate. 224 */ 225 DECLINLINE(const char *) GstCtrlHostFnName(enum eHostFn enmFunction) 226 { 227 switch (enmFunction) 228 { 229 RT_CASE_RET_STR(HOST_CANCEL_PENDING_WAITS); 230 RT_CASE_RET_STR(HOST_SESSION_CREATE); 231 RT_CASE_RET_STR(HOST_SESSION_CLOSE); 232 RT_CASE_RET_STR(HOST_EXEC_CMD); 233 RT_CASE_RET_STR(HOST_EXEC_SET_INPUT); 234 RT_CASE_RET_STR(HOST_EXEC_GET_OUTPUT); 235 RT_CASE_RET_STR(HOST_EXEC_TERMINATE); 236 RT_CASE_RET_STR(HOST_EXEC_WAIT_FOR); 237 RT_CASE_RET_STR(HOST_FILE_OPEN); 238 RT_CASE_RET_STR(HOST_FILE_CLOSE); 239 RT_CASE_RET_STR(HOST_FILE_READ); 240 RT_CASE_RET_STR(HOST_FILE_READ_AT); 241 RT_CASE_RET_STR(HOST_FILE_WRITE); 242 RT_CASE_RET_STR(HOST_FILE_WRITE_AT); 243 RT_CASE_RET_STR(HOST_FILE_SEEK); 244 RT_CASE_RET_STR(HOST_FILE_TELL); 245 RT_CASE_RET_STR(HOST_DIR_REMOVE); 246 RT_CASE_RET_STR(HOST_PATH_RENAME); 247 RT_CASE_RET_STR(HOST_PATH_USER_DOCUMENTS); 248 RT_CASE_RET_STR(HOST_PATH_USER_HOME); 249 } 250 return "Unknown"; 251 } 252 253 206 254 /** 207 255 * The service functions which are called by guest. The numbers may not change, … … 210 258 enum eGuestFn 211 259 { 212 /** 213 * Guest waits for a new message the host wants to process on the guest side. 260 /** Guest waits for a new message the host wants to process on the guest side. 214 261 * This is a blocking call and can be deferred. 215 262 * … … 231 278 */ 232 279 GUEST_MSG_WAIT = 1, 233 /** 234 * Guest asks the host to cancel all pending waits the guest itself waits on. 235 * This becomes necessary when the guest wants to quit but still waits for 236 * commands from the host. 237 */ 238 GUEST_CANCEL_PENDING_WAITS = 2, 239 /** 240 * Guest disconnected (terminated normally or due to a crash HGCM 280 /** Cancels pending calls for this client session. 281 * 282 * This should be used if a GUEST_MSG_PEEK_WAIT or GUEST_MSG_WAIT call gets 283 * interrupted on the client end, so as to prevent being rebuffed with 284 * VERR_RESOURCE_BUSY when restarting the call. 285 * 286 * @retval VINF_SUCCESS if cancelled any calls. 287 * @retval VWRN_NOT_FOUND if no callers. 288 * @retval VERR_INVALID_CLIENT_ID 289 * @retval VERR_WRONG_PARAMETER_COUNT 290 * @since 6.0 291 */ 292 GUEST_MSG_CANCEL = 2, 293 /** Guest disconnected (terminated normally or due to a crash HGCM 241 294 * detected when calling service::clientDisconnect(). 295 * 296 * @note This is a host side notification message that has no business in this 297 * enum. The guest cannot use this function number, host will reject it. 242 298 */ 243 299 GUEST_DISCONNECTED = 3, 244 /** 245 * Sets a message filter to only get messages which have a certain 300 /** Sets a message filter to only get messages which have a certain 246 301 * context ID scheme (that is, a specific session, object etc). 247 302 * Since VBox 4.3+. 303 * @deprecated Replaced by GUEST_SESSION_ACCEPT. 248 304 */ 249 305 GUEST_MSG_FILTER_SET = 4, 250 /** 251 * Unsets (and resets) a previously set message filter. 306 /** Unsets (and resets) a previously set message filter. 307 * @retval VERR_NOT_IMPLEMENTED since 6.0. 308 * @deprecated Never needed or used, 252 309 */ 253 310 GUEST_MSG_FILTER_UNSET = 5, 254 /**255 * Skips the current assigned message returned by GUEST_MSG_WAIT.256 * Needed for telling the host service to not keep stale257 * host commands in the queue.258 */259 GUEST_MSG_SKIP = 10,260 /**261 * General reply to a host message. Only contains basic data262 * along with a simple payload.263 */264 GUEST_MSG_REPLY = 11,265 /**266 * General message for updating a pending progress for267 * a long task.268 */269 GUEST_MSG_PROGRESS_UPDATE = 12,270 271 311 /** Peeks at the next message, returning immediately. 272 312 * … … 279 319 * @retval VINF_SUCCESS if a message was pending and is being returned. 280 320 * @retval VERR_TRY_AGAIN if no message pending. 281 * @retval VERR_INVALID_HANDLE if invalid client ID. 282 * @retval VERR_INVALID_PARAMETER if incorrect parameter count or types. 321 * @retval VERR_INVALID_CLIENT_ID 322 * @retval VERR_WRONG_PARAMETER_COUNT 323 * @retval VERR_WRONG_PARAMETER_TYPE 283 324 * @since 6.0 284 325 */ 285 GUEST_MSG_PEEK_NOWAIT ,326 GUEST_MSG_PEEK_NOWAIT = 6, 286 327 /** Peeks at the next message, waiting for one to arrive. 287 328 * … … 294 335 * @retval VINF_SUCCESS if info about an pending message is being returned. 295 336 * @retval VINF_TRY_AGAIN and message set to HOST_CANCEL_PENDING_WAITS if 296 * cancelled by GUEST_MSG_CANCEL or GUEST_CANCEL_PENDING_WAITS.337 * cancelled by GUEST_MSG_CANCEL. 297 338 * @retval VERR_RESOURCE_BUSY if another thread already made a waiting call. 298 * @retval VERR_INVALID_HANDLE if invalid client ID. 299 * @retval VERR_INVALID_PARAMETER if incorrect parameter count or types. 339 * @retval VERR_INVALID_CLIENT_ID 340 * @retval VERR_WRONG_PARAMETER_COUNT 341 * @retval VERR_WRONG_PARAMETER_TYPE 300 342 * @note This replaces GUEST_MSG_WAIT. 301 343 * @since 6.0 302 344 */ 303 GUEST_MSG_PEEK_WAIT ,345 GUEST_MSG_PEEK_WAIT = 7, 304 346 /** Gets the next message, returning immediately. 305 347 * … … 313 355 * @retval VERR_TRY_AGAIN if no message pending. 314 356 * @retval VERR_MISMATCH if the incoming message ID does not match the pending. 315 * @retval VERR_OUT_OF_RANGE if the wrong parameter count.316 * @retval VERR_WRONG_TYPE if a parameter has the wrong type.317 357 * @retval VERR_BUFFER_OVERFLOW if a parmeter buffer is too small. The buffer 318 358 * size was updated to reflect the required size. 319 * @retval VERR_INVALID_HANDLE if invalid client ID. 359 * @retval VERR_INVALID_CLIENT_ID 360 * @retval VERR_WRONG_PARAMETER_COUNT 361 * @retval VERR_WRONG_PARAMETER_TYPE 320 362 * @note This replaces GUEST_MSG_WAIT. 321 363 * @since 6.0 322 364 */ 323 GUEST_MSG_GET, 324 /** Cancels pending calls for this client session. 325 * 326 * This should be used if a GUEST_MSG_PEEK_WAIT or GUEST_MSG_WAIT call gets 327 * interrupted on the client end, so as to prevent being rebuffed with 328 * VERR_RESOURCE_BUSY when restarting the call. 329 * 330 * @retval VINF_SUCCESS if cancelled any calls. 331 * @retval VWRN_NOT_FOUND if no callers. 332 * @retval VERR_INVALID_PARAMETER if any parameters specified (expects zero). 333 * @retval VERR_INVALID_HANDLE if invalid client ID. 365 GUEST_MSG_GET = 8, 366 /** Skip message. 367 * 368 * This skips the current message, replying to the sender with 369 * VERR_NOT_SUPPORTED if appropriate. No parameters. 370 * 371 * @retval VINF_SUCCESS on success. 372 * @retval VERR_NOT_FOUND if no message pending. 373 * @retval VERR_INVALID_CLIENT_ID 374 * @retval VERR_WRONG_PARAMETER_COUNT 334 375 * @since 6.0 335 376 */ 336 GUEST_MSG_CANCEL, 337 377 GUEST_MSG_SKIP = 9, 378 /** 379 * Skips the current assigned message returned by GUEST_MSG_WAIT. 380 * Needed for telling the host service to not keep stale 381 * host commands in the queue. 382 * @deprecated Replaced by GUEST_MSG_SKIP. 383 */ 384 GUEST_MSG_SKIP_OLD = 10, 385 /** General reply to a host message. 386 * Only contains basic data along with a simple payload. 387 * @todo proper docs. 388 */ 389 GUEST_MSG_REPLY = 11, 390 /** General message for updating a pending progress for a long task. 391 * @todo proper docs. 392 */ 393 GUEST_MSG_PROGRESS_UPDATE = 12, 394 /** Sets the caller as the master. 395 * 396 * Called by the root VBoxService to explicitly tell the host that's the master 397 * service. Required to use main VBoxGuest device node. No parameters. 398 * 399 * @retval VINF_SUCCESS on success. 400 * @retval VERR_ACCESS_DENIED if not using main VBoxGuest device not 401 * @retval VERR_RESOURCE_BUSY if there is already a master. 402 * @retval VERR_VERSION_MISMATCH if VBoxGuest didn't supply requestor info. 403 * @retval VERR_INVALID_CLIENT_ID 404 * @retval VERR_WRONG_PARAMETER_COUNT 405 * @since 6.0 406 */ 407 GUEST_MAKE_ME_MASTER = 13, 408 /** Prepares the starting of a session. 409 * 410 * VBoxService makes this call before spawning a session process (must be 411 * master). The first parameter is the session ID and the second is a one time 412 * key for identifying the right session process. First parameter is a 32-bit 413 * session ID with a value between 1 and 0xfff0. The second parameter is a byte 414 * buffer containing a key that GUEST_SESSION_ACCEPT checks against, minimum 415 * length is 64 bytes, maximum 16384 bytes. 416 * 417 * @retval VINF_SUCCESS on success. 418 * @retval VERR_OUT_OF_RESOURCES if too many pending sessions hanging around. 419 * @retval VERR_OUT_OF_RANGE if the session ID outside the allowed range. 420 * @retval VERR_BUFFER_OVERFLOW if key too large. 421 * @retval VERR_BUFFER_UNDERFLOW if key too small. 422 * @retval VERR_ACCESS_DENIED if not master or in legacy mode. 423 * @retval VERR_DUPLICATE if the session ID has been prepared already. 424 * @retval VERR_INVALID_CLIENT_ID 425 * @retval VERR_WRONG_PARAMETER_COUNT 426 * @retval VERR_WRONG_PARAMETER_TYPE 427 * @since 6.0 428 */ 429 GUEST_SESSION_PREPARE = 14, 430 /** Cancels a prepared session. 431 * 432 * VBoxService makes this call to clean up after spawning a session process 433 * failed. One parameter, 32-bit session ID. If UINT32_MAX is passed, all 434 * prepared sessions are cancelled. 435 * 436 * @retval VINF_SUCCESS on success. 437 * @retval VWRN_NOT_FOUND if no session with the specified ID. 438 * @retval VERR_ACCESS_DENIED if not master or in legacy mode. 439 * @retval VERR_INVALID_CLIENT_ID 440 * @retval VERR_WRONG_PARAMETER_COUNT 441 * @retval VERR_WRONG_PARAMETER_TYPE 442 * @since 6.0 443 */ 444 GUEST_SESSION_CANCEL_PREPARED = 15, 445 /** Accepts a prepared session. 446 * 447 * The session processes makes this call to accept a prepared session. The 448 * session ID is then uniquely associated with the HGCM client ID of the caller. 449 * The parameters must be identical to the matching GUEST_SESSION_PREPARE call. 450 * 451 * @retval VINF_SUCCESS on success. 452 * @retval VERR_NOT_FOUND if the specified session ID wasn't found. 453 * @retval VERR_OUT_OF_RANGE if the session ID outside the allowed range. 454 * @retval VERR_BUFFER_OVERFLOW if key too large. 455 * @retval VERR_BUFFER_UNDERFLOW if key too small. 456 * @retval VERR_ACCESS_DENIED if we're in legacy mode or is master. 457 * @retval VERR_RESOURCE_BUSY if the client is already associated with a session. 458 * @retval VERR_MISMATCH if the key didn't match. 459 * @retval VERR_INVALID_CLIENT_ID 460 * @retval VERR_WRONG_PARAMETER_COUNT 461 * @retval VERR_WRONG_PARAMETER_TYPE 462 * @since 6.0 463 */ 464 GUEST_SESSION_ACCEPT = 16, 338 465 /** 339 466 * Guest reports back a guest session status. 467 * @todo proper docs. 340 468 */ 341 469 GUEST_SESSION_NOTIFY = 20, 342 470 /** 343 471 * Guest wants to close a specific guest session. 472 * @todo proper docs. 344 473 */ 345 474 GUEST_SESSION_CLOSE = 21, … … 347 476 /** 348 477 * Guests sends output from an executed process. 478 * @todo proper docs. 349 479 */ 350 480 GUEST_EXEC_OUTPUT = 100, 351 481 /** 352 482 * Guest sends a status update of an executed process to the host. 483 * @todo proper docs. 353 484 */ 354 485 GUEST_EXEC_STATUS = 101, 355 486 /** 356 487 * Guests sends an input status notification to the host. 488 * @todo proper docs. 357 489 */ 358 490 GUEST_EXEC_INPUT_STATUS = 102, … … 362 494 * how many data is available / can be sent without actually 363 495 * transmitting the data. 496 * @todo proper docs. 364 497 */ 365 498 GUEST_EXEC_IO_NOTIFY = 210, 366 499 /** 367 500 * Guest notifies the host about some directory event. 501 * @todo proper docs. 368 502 */ 369 503 GUEST_DIR_NOTIFY = 230, 370 504 /** 371 505 * Guest notifies the host about some file event. 506 * @todo proper docs. 372 507 */ 373 508 GUEST_FILE_NOTIFY = 240 374 509 }; 510 511 /** 512 * Translates a guest control host function function enum to at string. 513 * @returns Enum string name. 514 * @param enmFunction The function name to translate. 515 */ 516 DECLINLINE(const char *) GstCtrlGuestFnName(enum eGuestFn enmFunction) 517 { 518 switch (enmFunction) 519 { 520 RT_CASE_RET_STR(GUEST_MSG_WAIT); 521 RT_CASE_RET_STR(GUEST_MSG_CANCEL); 522 RT_CASE_RET_STR(GUEST_DISCONNECTED); 523 RT_CASE_RET_STR(GUEST_MSG_FILTER_SET); 524 RT_CASE_RET_STR(GUEST_MSG_FILTER_UNSET); 525 RT_CASE_RET_STR(GUEST_MSG_PEEK_NOWAIT); 526 RT_CASE_RET_STR(GUEST_MSG_PEEK_WAIT); 527 RT_CASE_RET_STR(GUEST_MSG_GET); 528 RT_CASE_RET_STR(GUEST_MSG_SKIP_OLD); 529 RT_CASE_RET_STR(GUEST_MSG_REPLY); 530 RT_CASE_RET_STR(GUEST_MSG_PROGRESS_UPDATE); 531 RT_CASE_RET_STR(GUEST_MSG_SKIP); 532 RT_CASE_RET_STR(GUEST_MAKE_ME_MASTER); 533 RT_CASE_RET_STR(GUEST_SESSION_PREPARE); 534 RT_CASE_RET_STR(GUEST_SESSION_CANCEL_PREPARED); 535 RT_CASE_RET_STR(GUEST_SESSION_ACCEPT); 536 RT_CASE_RET_STR(GUEST_SESSION_NOTIFY); 537 RT_CASE_RET_STR(GUEST_SESSION_CLOSE); 538 RT_CASE_RET_STR(GUEST_EXEC_OUTPUT); 539 RT_CASE_RET_STR(GUEST_EXEC_STATUS); 540 RT_CASE_RET_STR(GUEST_EXEC_INPUT_STATUS); 541 RT_CASE_RET_STR(GUEST_EXEC_IO_NOTIFY); 542 RT_CASE_RET_STR(GUEST_DIR_NOTIFY); 543 RT_CASE_RET_STR(GUEST_FILE_NOTIFY); 544 } 545 return "Unknown"; 546 } 547 375 548 376 549 /** -
trunk/include/VBox/VBoxGuestLib.h
r75758 r75798 768 768 VBGLR3DECL(int) VbglR3GuestCtrlDisconnect(uint32_t idClient); 769 769 VBGLR3DECL(int) VbglR3GuestCtrlMsgFilterSet(uint32_t uClientId, uint32_t uValue, uint32_t uMaskAdd, uint32_t uMaskRemove); 770 VBGLR3DECL(int) VbglR3GuestCtrlMsgFilterUnset(uint32_t uClientId);771 770 VBGLR3DECL(int) VbglR3GuestCtrlMsgReply(PVBGLR3GUESTCTRLCMDCTX pCtx, int rc); 772 771 VBGLR3DECL(int) VbglR3GuestCtrlMsgReplyEx(PVBGLR3GUESTCTRLCMDCTX pCtx, int rc, uint32_t uType, 773 772 void *pvPayload, uint32_t cbPayload); 774 VBGLR3DECL(int) VbglR3GuestCtrlMsgSkip (uint32_t uClientId);773 VBGLR3DECL(int) VbglR3GuestCtrlMsgSkipOld(uint32_t uClientId); 775 774 VBGLR3DECL(int) VbglR3GuestCtrlMsgPeekWait(uint32_t idClient, uint32_t *pidMsg, uint32_t *pcParameters); 776 775 VBGLR3DECL(int) VbglR3GuestCtrlCancelPendingWaits(HGCMCLIENTID idClient); -
trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibGuestCtrl.cpp
r75758 r75798 366 366 367 367 368 /**369 * Disables a previously set message filter.370 *371 * @return IPRT status code.372 * @param uClientId The client ID returned by VbglR3GuestCtrlConnect().373 */374 VBGLR3DECL(int) VbglR3GuestCtrlMsgFilterUnset(uint32_t uClientId)375 {376 /* Tell the host we want to unset the filter. */377 HGCMMsgCmdFilterUnset Msg;378 VBGL_HGCM_HDR_INIT(&Msg.hdr, uClientId, GUEST_MSG_FILTER_UNSET, 1);379 VbglHGCMParmUInt32Set(&Msg.flags, 0 /* Flags, unused */);380 381 return VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));382 }383 384 385 368 VBGLR3DECL(int) VbglR3GuestCtrlMsgReply(PVBGLR3GUESTCTRLCMDCTX pCtx, 386 369 int rc) … … 416 399 * @param uClientId The client ID returned by VbglR3GuestCtrlConnect(). 417 400 */ 418 VBGLR3DECL(int) VbglR3GuestCtrlMsgSkip (uint32_t uClientId)401 VBGLR3DECL(int) VbglR3GuestCtrlMsgSkipOld(uint32_t uClientId) 419 402 { 420 403 HGCMMsgCmdSkip Msg; 421 404 422 405 /* Tell the host we want to skip the current assigned command. */ 423 VBGL_HGCM_HDR_INIT(&Msg.hdr, uClientId, GUEST_MSG_SKIP , 1);406 VBGL_HGCM_HDR_INIT(&Msg.hdr, uClientId, GUEST_MSG_SKIP_OLD, 1); 424 407 VbglHGCMParmUInt32Set(&Msg.flags, 0 /* Flags, unused */); 425 408 return VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); … … 436 419 { 437 420 HGCMMsgCancelPendingWaits Msg; 438 VBGL_HGCM_HDR_INIT(&Msg.hdr, uClientId, GUEST_ CANCEL_PENDING_WAITS, 0);421 VBGL_HGCM_HDR_INIT(&Msg.hdr, uClientId, GUEST_MSG_CANCEL, 0); 439 422 return VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); 440 423 } -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp
r75758 r75798 361 361 * skip all not wanted messages here. 362 362 */ 363 rc = VbglR3GuestCtrlMsgSkip (g_uControlSvcClientID);363 rc = VbglR3GuestCtrlMsgSkipOld(g_uControlSvcClientID); 364 364 VGSvcVerbose(3, "Skipping uMsg=%RU32, cParms=%RU32, rc=%Rrc\n", uMsg, cParms, rc); 365 365 } -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlSession.cpp
r75758 r75798 1067 1067 VGSvcVerbose(3, "Unsupported message (uMsg=%RU32, cParms=%RU32) from host, skipping\n", uMsg, pHostCtx->uNumParms); 1068 1068 1069 /** @todo r=bird: Why on earth couldn't you make GUEST_MSG_SKIP do this hacky stuff?!?1070 * You don't even know if you're replying to a message ment for you (see masking race further down). */1071 1072 1069 /* 1073 1070 * !!! HACK ALERT BEGIN !!! … … 1103 1100 1104 1101 /* Tell the host service to skip the message. */ 1105 VbglR3GuestCtrlMsgSkip (pHostCtx->uClientID);1102 VbglR3GuestCtrlMsgSkipOld(pHostCtx->uClientID); 1106 1103 1107 1104 rc = VINF_SUCCESS; -
trunk/src/VBox/HostServices/GuestControl/service.cpp
r75773 r75798 60 60 * Header Files * 61 61 *********************************************************************************************************************************/ 62 #ifdef LOG_GROUP63 #undef LOG_GROUP64 #endif65 62 #define LOG_GROUP LOG_GROUP_GUEST_CONTROL 66 63 #include <VBox/HostServices/GuestControlSvc.h> … … 68 65 #include <VBox/log.h> 69 66 #include <VBox/AssertGuest.h> 67 #include <VBox/VMMDev.h> 70 68 #include <iprt/assert.h> 71 69 #include <iprt/cpp/autores.h> … … 80 78 81 79 #include <map> 82 #include < memory> /* for auto_ptr*/80 #include <new> /* for std::nothrow*/ 83 81 #include <string> 84 82 #include <list> 85 83 86 84 87 namespace guestControl { 88 89 /** Flag for indicating that the client only is interested in 90 * messages of specific context IDs. */ 91 #define CLIENTSTATE_FLAG_CONTEXTFILTER RT_BIT(0) 85 using namespace guestControl; 86 92 87 93 88 /** … … 114 109 typedef struct HostCommand 115 110 { 116 RTLISTNODE Node; 117 118 uint32_t AddRef(void) 119 { 120 #ifdef DEBUG_andy 121 LogFlowThisFunc(("[Cmd %RU32] Adding reference, new refCount=%RU32\n", mMsgType, mRefCount + 1)); 122 #endif 123 return ++mRefCount; 124 } 125 126 uint32_t Release(void) 127 { 128 #ifdef DEBUG_andy 129 LogFlowThisFunc(("[Cmd %RU32] Releasing reference, new refCount=%RU32\n", mMsgType, mRefCount - 1)); 130 #endif 131 /* Release reference for current command. */ 132 Assert(mRefCount); 133 if (--mRefCount == 0) 134 Free(); 135 136 return mRefCount; 111 /** Entry on the GstCtrlService::mHostCmdList list. */ 112 RTLISTNODE m_ListEntry; 113 /** Reference counter for facilitating sending to both session and root. */ 114 uint32_t m_cRefs; 115 union 116 { 117 /** The top two twomost bits are exploited for message destination. 118 * See VBOX_GUESTCTRL_DST_XXX. */ 119 uint64_t m_idContextAndDst; 120 /** The context ID this command belongs to (extracted from the first parameter). */ 121 uint32_t m_idContext; 122 }; 123 /** Dynamic structure for holding the HGCM parms */ 124 uint32_t mMsgType; 125 /** Number of HGCM parameters. */ 126 uint32_t mParmCount; 127 /** Array of HGCM parameters. */ 128 PVBOXHGCMSVCPARM mpParms; 129 130 HostCommand() 131 : m_cRefs(1) 132 , m_idContextAndDst(0) 133 , mMsgType(UINT32_MAX) 134 , mParmCount(0) 135 , mpParms(NULL) 136 { 137 RTListInit(&m_ListEntry); 137 138 } 138 139 139 140 /** 140 * Allocates the command with an HGCM request - or put more accurately, it 141 * duplicates the given HGCM reguest (it does not allocate a HostCommand). 141 * Retains a reference to the command. 142 */ 143 uint32_t Retain(void) 144 { 145 uint32_t cRefs = ++m_cRefs; 146 Log4(("[Cmd %RU32 (%s)] Adding reference, new m_cRefs=%u\n", mMsgType, GstCtrlHostFnName((eHostFn)mMsgType), cRefs)); 147 Assert(cRefs < 4); 148 return cRefs; 149 } 150 151 /** 152 * Releases the host command, properly deleting it if no further references. 153 */ 154 uint32_t SaneRelease(void) 155 { 156 uint32_t cRefs = --m_cRefs; 157 Log4(("[Cmd %RU32] sane release - cRefs=%u\n", mMsgType, cRefs)); 158 Assert(cRefs < 4); 159 160 if (!cRefs) 161 { 162 LogFlowThisFunc(("[Cmd %RU32 (%s)] destroying\n", mMsgType, GstCtrlHostFnName((eHostFn)mMsgType))); 163 RTListNodeRemove(&m_ListEntry); 164 if (mpParms) 165 { 166 for (uint32_t i = 0; i < mParmCount; i++) 167 if (mpParms[i].type == VBOX_HGCM_SVC_PARM_PTR) 168 { 169 RTMemFree(mpParms[i].u.pointer.addr); 170 mpParms[i].u.pointer.addr = NULL; 171 } 172 RTMemFree(mpParms); 173 mpParms = NULL; 174 } 175 mParmCount = 0; 176 delete this; 177 } 178 return cRefs; 179 } 180 181 /** 182 * Initializes the command. 142 183 * 143 * Needs to be freed using Free(). 184 * The specified parameters are copied and any buffers referenced by it 185 * duplicated as well. 144 186 * 145 187 * @return IPRT status code. 146 * @param uMsg Message type. 147 * @param cParms Number of parameters of HGCM request. 148 * @param paParms Array of parameters of HGCM request. 149 */ 150 int Allocate(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 151 { 152 LogFlowThisFunc(("[Cmd %RU32] Allocating cParms=%RU32, paParms=%p\n", uMsg, cParms, paParms)); 153 154 if (!cParms) /* At least one parameter (context ID) must be present. */ 155 return VERR_INVALID_PARAMETER; 156 188 * @param idFunction The host function (message) number, eHostFn. 189 * @param cParms Number of parameters in the HGCM request. 190 * @param paParms Array of parameters. 191 */ 192 int Init(uint32_t idFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 193 { 194 LogFlowThisFunc(("[Cmd %RU32 (%s)] Allocating cParms=%RU32, paParms=%p\n", 195 idFunction, GstCtrlHostFnName((eHostFn)idFunction), cParms, paParms)); 196 Assert(mpParms == NULL); 197 Assert(mParmCount == 0); 198 Assert(m_cRefs == 1); 199 200 /* 201 * Fend of bad stuff. 202 */ 203 AssertReturn(cParms > 0, VERR_WRONG_PARAMETER_COUNT); /* At least one parameter (context ID) must be present. */ 204 AssertReturn(cParms < VMMDEV_MAX_HGCM_PARMS, VERR_WRONG_PARAMETER_COUNT); 157 205 AssertPtrReturn(paParms, VERR_INVALID_POINTER); 158 206 159 /* Paranoia. */160 if (cParms > 256)161 cParms = 256;162 163 int rc = VINF_SUCCESS;164 165 207 /* 166 * Don't verify anything here (yet), because this function only buffers 167 * the HGCM data into an internal structure and reaches it back to the guest (client) 168 * in an unmodified state. 208 * The first parameter is the context ID and the command destiation mask. 169 209 */ 170 mMsgType = uMsg; 210 if (paParms[0].type == VBOX_HGCM_SVC_PARM_64BIT) 211 { 212 m_idContextAndDst = paParms[0].u.uint64; 213 AssertReturn(m_idContextAndDst & VBOX_GUESTCTRL_DST_BOTH, VERR_INTERNAL_ERROR_3); 214 } 215 else if (paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT) 216 { 217 AssertMsgFailed(("idFunction=%u %s - caller must set dst!\n", idFunction, GstCtrlHostFnName((eHostFn)idFunction))); 218 m_idContextAndDst = paParms[0].u.uint32 | VBOX_GUESTCTRL_DST_BOTH; 219 } 220 else 221 AssertFailedReturn(VERR_WRONG_PARAMETER_TYPE); 222 223 /* 224 * Just make a copy of the parameters and any buffers. 225 */ 226 mMsgType = idFunction; 171 227 mParmCount = cParms; 172 if (mParmCount) 173 { 174 mpParms = (VBOXHGCMSVCPARM *)RTMemAllocZ(sizeof(VBOXHGCMSVCPARM) * mParmCount); 175 if (NULL == mpParms) 176 rc = VERR_NO_MEMORY; 177 } 178 179 if (RT_SUCCESS(rc)) 180 { 181 for (uint32_t i = 0; i < mParmCount; i++) 228 mpParms = (VBOXHGCMSVCPARM *)RTMemAllocZ(sizeof(VBOXHGCMSVCPARM) * mParmCount); 229 AssertReturn(mpParms, VERR_NO_MEMORY); 230 231 for (uint32_t i = 0; i < cParms; i++) 232 { 233 mpParms[i].type = paParms[i].type; 234 switch (paParms[i].type) 182 235 { 183 mpParms[i].type = paParms[i].type; 184 switch (paParms[i].type) 185 { 186 case VBOX_HGCM_SVC_PARM_32BIT: 187 mpParms[i].u.uint32 = paParms[i].u.uint32; 188 break; 189 190 case VBOX_HGCM_SVC_PARM_64BIT: 191 mpParms[i].u.uint64 = paParms[i].u.uint64; 192 break; 193 194 case VBOX_HGCM_SVC_PARM_PTR: 195 mpParms[i].u.pointer.size = paParms[i].u.pointer.size; 196 if (mpParms[i].u.pointer.size > 0) 197 { 198 mpParms[i].u.pointer.addr = RTMemAlloc(mpParms[i].u.pointer.size); 199 if (mpParms[i].u.pointer.addr != NULL) 200 memcpy(mpParms[i].u.pointer.addr, 201 paParms[i].u.pointer.addr, 202 mpParms[i].u.pointer.size); 203 else 204 rc = VERR_NO_MEMORY; 205 } 206 else 207 { 208 /* Size is 0 -- make sure we don't have any pointer. */ 209 mpParms[i].u.pointer.addr = NULL; 210 } 211 break; 212 213 default: 214 break; 215 } 216 if (RT_FAILURE(rc)) 236 case VBOX_HGCM_SVC_PARM_32BIT: 237 mpParms[i].u.uint32 = paParms[i].u.uint32; 217 238 break; 239 240 case VBOX_HGCM_SVC_PARM_64BIT: 241 mpParms[i].u.uint64 = paParms[i].u.uint64; 242 break; 243 244 case VBOX_HGCM_SVC_PARM_PTR: 245 mpParms[i].u.pointer.size = paParms[i].u.pointer.size; 246 if (mpParms[i].u.pointer.size > 0) 247 { 248 mpParms[i].u.pointer.addr = RTMemDup(paParms[i].u.pointer.addr, mpParms[i].u.pointer.size); 249 AssertReturn(mpParms[i].u.pointer.addr, VERR_NO_MEMORY); 250 } 251 /* else: structure is zeroed by allocator. */ 252 break; 253 254 default: 255 AssertMsgFailedReturn(("idFunction=%u (%s) parameter #%u: type=%u\n", 256 idFunction, GstCtrlHostFnName((eHostFn)idFunction), i, paParms[i].type), 257 VERR_WRONG_PARAMETER_TYPE); 218 258 } 219 259 } 220 260 221 if (RT_SUCCESS(rc)) 222 { 223 /* 224 * Assume that the context ID *always* is the first parameter, 225 * assign the context ID to the command. 226 */ 227 rc = HGCMSvcGetU32(&mpParms[0], &mContextID); 228 229 /* Set timestamp so that clients can distinguish between already 230 * processed commands and new ones. */ 231 mTimestamp = RTTimeNanoTS(); 232 } 233 234 LogFlowFunc(("Returned with rc=%Rrc\n", rc)); 235 return rc; 236 } 237 238 /** 239 * Frees the buffered HGCM request (not the HostCommand structure itself). 240 */ 241 void Free(void) 242 { 243 AssertMsg(mRefCount == 0, ("uMsg=%RU32, CID=%RU32 still being used by a client (%RU32 refs), cannot free yet\n", 244 mMsgType, mContextID, mRefCount)); 245 246 LogFlowThisFunc(("[Cmd %RU32] Freeing\n", mMsgType)); 247 248 for (uint32_t i = 0; i < mParmCount; i++) 249 { 250 switch (mpParms[i].type) 251 { 252 case VBOX_HGCM_SVC_PARM_PTR: 253 if (mpParms[i].u.pointer.size > 0) 254 RTMemFree(mpParms[i].u.pointer.addr); 255 break; 256 257 default: 258 break; 259 } 260 } 261 262 if (mpParms) 263 { 264 RTMemFree(mpParms); 265 mpParms = NULL; 266 } 267 268 mParmCount = 0; 269 270 /* Removes the command from its list */ 271 RTListNodeRemove(&Node); 272 } 261 /* 262 * Morph the first parameter back to 32-bit. 263 */ 264 mpParms[0].type = VBOX_HGCM_SVC_PARM_32BIT; 265 mpParms[0].u.uint32 = (uint32_t)paParms[0].u.uint64; 266 267 return VINF_SUCCESS; 268 } 269 273 270 274 271 /** … … 282 279 int CopyTo(VBOXHGCMSVCPARM paDstParms[], uint32_t cDstParms) const 283 280 { 284 LogFlowThisFunc(("[Cmd %RU32] mParmCount=%RU32, m ContextID=%RU32 (Session %RU32)\n",285 mMsgType, mParmCount, m ContextID, VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(mContextID)));281 LogFlowThisFunc(("[Cmd %RU32] mParmCount=%RU32, m_idContext=%RU32 (Session %RU32)\n", 282 mMsgType, mParmCount, m_idContext, VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(m_idContext))); 286 283 287 284 int rc = VINF_SUCCESS; … … 423 420 return VERR_TOO_MUCH_DATA; 424 421 } 425 426 /** Reference count for keeping track how many connected427 * clients still need to process this command until it can428 * be removed. */429 uint32_t mRefCount;430 /** The context ID this command belongs to. Will be extracted431 * *always* from HGCM parameter [0]. */432 uint32_t mContextID;433 /** Dynamic structure for holding the HGCM parms */434 uint32_t mMsgType;435 /** Number of HGCM parameters. */436 uint32_t mParmCount;437 /** Array of HGCM parameters. */438 PVBOXHGCMSVCPARM mpParms;439 /** Incoming timestamp (nanoseconds). */440 uint64_t mTimestamp;441 422 } HostCommand; 442 423 typedef std::list< HostCommand *> HostCmdList; … … 467 448 { 468 449 ClientState(void) 469 : mSvcHelpers(NULL) ,470 mID(0),471 mFlags(0),472 mFilterMask(0), mFilterValue(0),473 mHostCmdRc(VINF_SUCCESS), mHostCmdTries(0),474 mHostCmdTS(0),475 mIsPending((guestControl::eGuestFn)0),476 mPeekCount(0)450 : mSvcHelpers(NULL) 451 , mID(0) 452 , mIsPending((guestControl::eGuestFn)0) 453 , m_fIsMaster(false) 454 , m_idSession(UINT32_MAX) 455 , mHostCmdRc(VINF_SUCCESS) 456 , mHostCmdTries(0) 457 , mPeekCount(0) 477 458 { } 478 459 479 ClientState(PVBOXHGCMSVCHELPERS pSvcHelpers, uint32_t uClientID)480 : mSvcHelpers(pSvcHelpers) ,481 mID(uClientID),482 mFlags(0),483 mFilterMask(0), mFilterValue(0),484 mHostCmdRc(VINF_SUCCESS), mHostCmdTries(0),485 mHostCmdTS(0),486 mIsPending((guestControl::eGuestFn)0),487 mPeekCount(0)460 ClientState(PVBOXHGCMSVCHELPERS pSvcHelpers, uint32_t idClient) 461 : mSvcHelpers(pSvcHelpers) 462 , mID(idClient) 463 , mIsPending((guestControl::eGuestFn)0) 464 , m_fIsMaster(false) 465 , m_idSession(UINT32_MAX) 466 , mHostCmdRc(VINF_SUCCESS) 467 , mHostCmdTries(0) 468 , mPeekCount(0) 488 469 { } 489 470 490 void DequeueAll(void) 491 { 492 HostCmdListIter curItem = mHostCmdList.begin(); 493 while (curItem != mHostCmdList.end()) 494 curItem = Dequeue(curItem); 495 } 496 497 void DequeueCurrent(void) 498 { 499 HostCmdListIter curCmd = mHostCmdList.begin(); 500 if (curCmd != mHostCmdList.end()) 501 Dequeue(curCmd); 502 } 503 504 HostCmdListIter Dequeue(HostCmdListIter &curItem) 505 { 506 HostCommand *pHostCmd = *curItem; 471 /** 472 * Ditches the first host command and crazy GUEST_MSG_WAIT state. 473 */ 474 void DitchFirstHostCmd() 475 { 476 Assert(!mHostCmdList.empty()); 477 HostCommand *pHostCmd = *mHostCmdList.begin(); 507 478 AssertPtr(pHostCmd); 508 509 if (pHostCmd->Release() == 0) 510 { 511 LogFlowThisFunc(("[Client %RU32] Destroying command %RU32\n", mID, pHostCmd->mMsgType)); 512 513 delete pHostCmd; 514 pHostCmd = NULL; 515 } 516 517 HostCmdListIter nextItem = mHostCmdList.erase(curItem); 518 519 /* Reset everything else. */ 479 pHostCmd->SaneRelease(); 480 mHostCmdList.pop_front(); 481 482 /* Reset state else. */ 520 483 mHostCmdRc = VINF_SUCCESS; 521 484 mHostCmdTries = 0; 522 485 mPeekCount = 0; 523 524 return nextItem;525 486 } 526 487 … … 529 490 AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER); 530 491 531 int rc = VINF_SUCCESS;532 533 492 try 534 493 { 535 494 mHostCmdList.push_back(pHostCmd); 536 pHostCmd->AddRef();537 495 } 538 496 catch (std::bad_alloc &) 539 497 { 540 rc = VERR_NO_MEMORY; 541 } 542 543 return rc; 544 } 545 546 #if 0 /* not used by anyone */ 547 /** Returns the pointer to the current host command in a client's list. 548 * NULL if no current command available. */ 549 const HostCommand *GetCurrent(void) 550 { 551 if (mHostCmdList.empty()) 552 return NULL; 553 554 return (*mHostCmdList.begin()); 555 } 556 #endif 557 558 bool WantsHostCommand(const HostCommand *pHostCmd) const 559 { 560 AssertPtrReturn(pHostCmd, false); 561 562 #ifdef DEBUG_andy 563 LogFlowFunc(("mHostCmdTS=%RU64, pHostCmdTS=%RU64\n", 564 mHostCmdTS, pHostCmd->mTimestamp)); 565 #endif 566 567 /* Only process newer commands. */ 568 /** @todo r=bird: This seems extremely bogus given that I cannot see 569 * ClientState::mHostCmdTS being set anywhere at all. */ 570 if (pHostCmd->mTimestamp <= mHostCmdTS) 571 return false; 572 573 /* 574 * If a session filter is set, only obey those commands we're interested in 575 * by applying our context ID filter mask and compare the result with the 576 * original context ID. 577 */ 578 bool fWant; 579 if (mFlags & CLIENTSTATE_FLAG_CONTEXTFILTER) 580 fWant = (pHostCmd->mContextID & mFilterMask) == mFilterValue; 581 else /* Client is interested in all commands. */ 582 fWant = true; 583 584 LogFlowFunc(("[Client %RU32] mFlags=0x%x, mContextID=%RU32 (session %RU32), mFilterMask=0x%x, mFilterValue=%RU32, fWant=%RTbool\n", 585 mID, mFlags, pHostCmd->mContextID, 586 VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(pHostCmd->mContextID), 587 mFilterMask, mFilterValue, fWant)); 588 589 return fWant; 498 return VERR_NO_MEMORY; 499 } 500 501 pHostCmd->Retain(); 502 return VINF_SUCCESS; 590 503 } 591 504 … … 640 553 * @note Only used by GUEST_MSG_WAIT scenarios. 641 554 */ 642 int OldRun(ClientConnection const *pConnection, 643 HostCommand *pHostCmd) 555 int OldRun(ClientConnection const *pConnection, HostCommand *pHostCmd) 644 556 { 645 557 AssertPtrReturn(pConnection, VERR_INVALID_POINTER); 646 558 AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER); 559 Assert(*mHostCmdList.begin() == pHostCmd); 647 560 648 561 LogFlowFunc(("[Client %RU32] pConnection=%p, mHostCmdRc=%Rrc, mHostCmdTries=%RU32, mPeekCount=%RU32\n", … … 691 604 if (fRemove) 692 605 { 693 /** @todo Fix this (slow) lookup. Too late today. */ 694 HostCmdListIter curItem = mHostCmdList.begin(); 695 while (curItem != mHostCmdList.end()) 696 { 697 if ((*curItem) == pHostCmd) 698 { 699 Dequeue(curItem); 700 break; 701 } 702 703 ++curItem; 704 } 606 Assert(*mHostCmdList.begin() == pHostCmd); 607 DitchFirstHostCmd(); 705 608 } 706 609 … … 758 661 AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER); 759 662 760 LogFlowThisFunc(("[Client %RU32] Current host command is %RU32 (CID=%RU32, cParms=%RU32, refCount=%RU32)\n",761 mID, pHostCmd->mMsgType, pHostCmd->m ContextID, pHostCmd->mParmCount, pHostCmd->mRefCount));663 LogFlowThisFunc(("[Client %RU32] Current host command is %RU32 (CID=%RU32, cParms=%RU32, m_cRefs=%RU32)\n", 664 mID, pHostCmd->mMsgType, pHostCmd->m_idContext, pHostCmd->mParmCount, pHostCmd->m_cRefs)); 762 665 763 666 if (mIsPending == GUEST_MSG_PEEK_WAIT) … … 791 694 792 695 /** 793 * Used by Service::call() to handle GUEST_ CANCEL_PENDING_WAITS.696 * Used by Service::call() to handle GUEST_MSG_CANCEL. 794 697 * 795 698 * @note This cancels both GUEST_MSG_WAIT and GUEST_MSG_PEEK_WAIT sleepers. … … 797 700 int CancelWaiting() 798 701 { 799 LogFlowFunc(("[Client %RU32] Cancelling waiting thread, isPending=%d, pendingNumParms=%RU32, flags=%x\n", 800 mID, mIsPending, mPendingCon.mNumParms, mFlags)); 702 LogFlowFunc(("[Client %RU32] Cancelling waiting thread, isPending=%d, pendingNumParms=%RU32, m_idSession=%x\n", 703 mID, mIsPending, mPendingCon.mNumParms, m_idSession)); 704 /** @todo r=bird: This must be made sticky if no pending call, i.e. next wait 705 * call must return immediately. otherwise there will be a race and 706 * occational long VBoxService shutdown times. */ 801 707 802 708 int rc; … … 892 798 /** The client's ID. */ 893 799 uint32_t mID; 894 /** Client flags. @sa CLIENTSTATE_FLAG_ flags. */895 uint32_t mFlags;896 /** The context ID filter mask, if any. */897 uint32_t mFilterMask;898 /** The context ID filter value, if any. */899 uint32_t mFilterValue;900 800 /** Host command list to process. */ 901 801 HostCmdList mHostCmdList; 802 /** Pending client call (GUEST_MSG_PEEK_WAIT or GUEST_MSG_WAIT), zero if none pending. 803 * 804 * This means the client waits for a new host command to reply and won't return 805 * from the waiting call until a new host command is available. */ 806 guestControl::eGuestFn mIsPending; 807 /** The client's pending connection. */ 808 ClientConnection mPendingCon; 809 /** Set if master. */ 810 bool m_fIsMaster; 811 /** The session ID for this client, UINT32_MAX if not set or master. */ 812 uint32_t m_idSession; 813 814 /** @name The GUEST_MSG_WAIT state. 815 * @note Don't try understand this, it is certificable! 816 * @{ */ 902 817 /** Last (most recent) rc after handling the host command. */ 903 818 int mHostCmdRc; … … 907 822 * to be able to successfully retrieve. */ 908 823 uint32_t mHostCmdTries; 909 /** Timestamp (nanoseconds) of last host command processed.910 * @todo r=bird: Where is this set? */911 uint64_t mHostCmdTS;912 /** Pending client call (GUEST_MSG_PEEK_WAIT or GUEST_MSG_WAIT), zero if none pending.913 *914 * This means the client waits for a new host command to reply and won't return915 * from the waiting call until a new host command is available.916 */917 guestControl::eGuestFn mIsPending;918 824 /** Number of times we've peeked at a pending message. 919 825 * … … 924 830 */ 925 831 uint32_t mPeekCount; 926 /** The client's pending connection.*/927 ClientConnection mPendingCon; 832 /** @} */ 833 928 834 } ClientState; 929 835 typedef std::map< uint32_t, ClientState > ClientStateMap; … … 932 838 933 839 /** 840 * Prepared session (GUEST_SESSION_PREPARE). 841 */ 842 typedef struct GstCtrlPreparedSession 843 { 844 /** List entry. */ 845 RTLISTNODE ListEntry; 846 /** The session ID. */ 847 uint32_t idSession; 848 /** The key size. */ 849 uint32_t cbKey; 850 /** The key bytes. */ 851 uint8_t abKey[RT_FLEXIBLE_ARRAY]; 852 } GstCtrlPreparedSession; 853 854 855 /** 934 856 * Class containing the shared information service functionality. 935 857 */ 936 class Service : public RTCNonCopyable858 class GstCtrlService : public RTCNonCopyable 937 859 { 938 860 … … 940 862 941 863 /** Type definition for use in callback functions. */ 942 typedef Service SELF;864 typedef GstCtrlService SELF; 943 865 /** HGCM helper functions. */ 944 866 PVBOXHGCMSVCHELPERS mpHelpers; 945 /** 946 * Callback function supplied by the host for notification of updates 947 * to properties. 948 */ 867 /** Callback function supplied by the host for notification of updates to properties. */ 949 868 PFNHGCMSVCEXT mpfnHostCallback; 950 869 /** User data pointer to be supplied to the host callback function. */ … … 952 871 /** List containing all buffered host commands. */ 953 872 RTLISTANCHOR mHostCmdList; 954 /** Map containing all connected clients. The primary key contains 955 * the HGCM client ID to identify the client. */ 956 ClientStateMap mClientStateMap; 873 /** Map containing all connected clients, key is HGCM client ID. */ 874 ClientStateMap mClientStateMap; 875 /** The master HGCM client ID, UINT32_MAX if none. */ 876 uint32_t m_idMasterClient; 877 /** Set if we're in legacy mode (pre 6.0). */ 878 bool m_fLegacyMode; 879 /** Number of prepared sessions. */ 880 uint32_t m_cPreparedSessions; 881 /** List of prepared session (GstCtrlPreparedSession). */ 882 RTLISTANCHOR m_PreparedSessions; 883 957 884 public: 958 explicit Service(PVBOXHGCMSVCHELPERS pHelpers)885 explicit GstCtrlService(PVBOXHGCMSVCHELPERS pHelpers) 959 886 : mpHelpers(pHelpers) 960 887 , mpfnHostCallback(NULL) 961 888 , mpvHostData(NULL) 889 , m_idMasterClient(UINT32_MAX) 890 , m_fLegacyMode(true) 891 , m_cPreparedSessions(0) 962 892 { 963 893 RTListInit(&mHostCmdList); 894 RTListInit(&m_PreparedSessions); 964 895 } 965 896 966 897 /** 967 898 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnUnload} 968 * Simply deletes the service object899 * Simply deletes the GstCtrlService object 969 900 */ 970 901 static DECLCALLBACK(int) svcUnload(void *pvService) … … 988 919 uint32_t fRequestor, bool fRestoring) 989 920 { 990 RT_NOREF(fRe questor, fRestoring);921 RT_NOREF(fRestoring); 991 922 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER); 992 923 SELF *pSelf = reinterpret_cast<SELF *>(pvService); 993 924 AssertPtrReturn(pSelf, VERR_INVALID_POINTER); 994 return pSelf->clientConnect(u32ClientID, pvClient );925 return pSelf->clientConnect(u32ClientID, pvClient, fRequestor); 995 926 } 996 927 … … 1063 994 1064 995 int prepareExecute(uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 1065 int clientConnect(uint32_t u32ClientID, void *pvClient );996 int clientConnect(uint32_t u32ClientID, void *pvClient, uint32_t fRequestor); 1066 997 int clientDisconnect(uint32_t u32ClientID, void *pvClient); 998 999 int clientMakeMeMaster(uint32_t idClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms); 1000 int clientMsgPeek(uint32_t idClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool fWait); 1001 int clientMsgGet(uint32_t idClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 1002 int clientMsgCancel(uint32_t idClient, uint32_t cParms); 1003 int clientMsgSkip(uint32_t idClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms); 1004 int clientSessionPrepare(uint32_t idClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 1005 int clientSessionCancelPrepared(uint32_t idClient, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 1006 int clientSessionAccept(uint32_t idClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 1007 int clientSessionCloseOther(uint32_t idClient, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 1008 1067 1009 int clientMsgOldGet(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 1068 int clientMsgPeek(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool fWait); 1069 int clientMsgGet(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 1070 int clientMsgCancel(uint32_t u32ClientID, uint32_t cParms); 1071 int clientMsgFilterSet(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 1072 int clientMsgFilterUnset(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 1073 int clientMsgSkip(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 1010 int clientMsgOldFilterSet(uint32_t u32ClientID, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 1011 int clientMsgOldSkip(uint32_t u32ClientID, uint32_t cParms); 1012 1074 1013 int hostCallback(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 1075 1014 int hostProcessCommand(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 1076 void call(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, void *pvClient, uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 1015 void call(VBOXHGCMCALLHANDLE hCall, uint32_t idClient, void *pvClient, uint32_t idFunction, 1016 uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 1077 1017 int hostCall(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 1078 int sessionClose(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);1079 1018 int uninit(void); 1080 1019 1081 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP( Service);1020 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(GstCtrlService); 1082 1021 }; 1083 1022 1023 1084 1024 /** 1085 1025 * Handles a client which just connected. 1086 1026 * 1087 1027 * @return IPRT status code. 1088 * @param u32ClientID1028 * @param idClient 1089 1029 * @param pvClient 1090 */ 1091 int Service::clientConnect(uint32_t u32ClientID, void *pvClient) 1030 * @param fRequestor VMMDevRequestHeader::fRequestor value, if available. 1031 */ 1032 int GstCtrlService::clientConnect(uint32_t idClient, void *pvClient, uint32_t fRequestor) 1092 1033 { 1093 1034 RT_NOREF(pvClient); 1094 LogFlowFunc(("[Client %RU32] Connected\n", u32ClientID)); 1095 #ifdef VBOX_STRICT 1096 ClientStateMapIterConst it = mClientStateMap.find(u32ClientID); 1097 if (it != mClientStateMap.end()) 1098 { 1099 AssertMsgFailed(("Client with ID=%RU32 already connected when it should not\n", 1100 u32ClientID)); 1101 return VERR_ALREADY_EXISTS; 1102 } 1103 #endif 1104 ClientState clientState(mpHelpers, u32ClientID); 1105 mClientStateMap[u32ClientID] = clientState; 1106 /** @todo Exception handling! */ 1035 LogFlowFunc(("[Client %RU32] Connected\n", idClient)); 1036 AssertMsg(mClientStateMap.find(idClient) == mClientStateMap.end(), 1037 ("Client with ID=%RU32 already connected when it should not\n", idClient)); 1038 1039 /* 1040 * Create client state. 1041 */ 1042 try 1043 { 1044 mClientStateMap[idClient] = ClientState(mpHelpers, idClient); 1045 } 1046 catch (std::bad_alloc) 1047 { 1048 return VERR_NO_MEMORY; 1049 } 1050 ClientState &rClientState = mClientStateMap[idClient]; 1051 1052 /* 1053 * For legacy compatibility reasons we have to pick a master client at some 1054 * point, so if the /dev/vboxguest requirements checks out we pick the first 1055 * one through the door. 1056 */ 1057 /** @todo make picking the master more dynamic/flexible. */ 1058 if ( m_fLegacyMode 1059 && m_idMasterClient == UINT32_MAX) 1060 { 1061 if ( fRequestor == VMMDEV_REQUESTOR_LEGACY 1062 || !(fRequestor & VMMDEV_REQUESTOR_USER_DEVICE)) 1063 { 1064 LogFunc(("Picking %u as master for now.\n", idClient)); 1065 m_idMasterClient = idClient; 1066 rClientState.m_fIsMaster = true; 1067 } 1068 } 1069 1107 1070 return VINF_SUCCESS; 1108 1071 } 1109 1072 1073 1110 1074 /** 1111 1075 * Handles a client which disconnected. … … 1115 1079 * 1116 1080 * @return IPRT status code. 1117 * @param u32ClientIDThe client's ID of which disconnected.1118 * @param pvClient User data, not used at the moment.1119 */ 1120 int Service::clientDisconnect(uint32_t u32ClientID, void *pvClient)1081 * @param idClient The client's ID of which disconnected. 1082 * @param pvClient User data, not used at the moment. 1083 */ 1084 int GstCtrlService::clientDisconnect(uint32_t idClient, void *pvClient) 1121 1085 { 1122 1086 RT_NOREF(pvClient); 1123 LogFlowFunc(("[Client %RU32] Disconnected (%zu clients total)\n", 1124 u32ClientID, mClientStateMap.size())); 1125 1126 AssertMsg(!mClientStateMap.empty(), 1127 ("No clients in list anymore when there should (client ID=%RU32)\n", u32ClientID)); 1128 1129 int rc = VINF_SUCCESS; 1130 1131 ClientStateMapIter itClientState = mClientStateMap.find(u32ClientID); 1132 AssertMsg(itClientState != mClientStateMap.end(), 1133 ("Client ID=%RU32 not found in client list when it should be there\n", u32ClientID)); 1134 1135 if (itClientState != mClientStateMap.end()) 1136 { 1137 itClientState->second.DequeueAll(); 1138 1139 mClientStateMap.erase(itClientState); 1140 } 1141 1142 bool fAllClientsDisconnected = mClientStateMap.empty(); 1143 if (fAllClientsDisconnected) 1144 { 1145 LogFlowFunc(("All clients disconnected, cancelling all host commands ...\n")); 1146 1147 /* 1148 * If all clients disconnected we also need to make sure that all buffered 1149 * host commands need to be notified, because Main is waiting a notification 1150 * via a (multi stage) progress object. 1151 */ 1152 /** @todo r=bird: We have RTListForEachSafe for this purpose... Would save a 1153 * few lines and bother here. */ 1154 HostCommand *pCurCmd = RTListGetFirst(&mHostCmdList, HostCommand, Node); 1155 while (pCurCmd) 1156 { 1157 HostCommand *pNext = RTListNodeGetNext(&pCurCmd->Node, HostCommand, Node); 1158 bool fLast = RTListNodeIsLast(&mHostCmdList, &pCurCmd->Node); 1159 1160 uint32_t cParms = 0; 1161 VBOXHGCMSVCPARM arParms[2]; 1162 HGCMSvcSetU32(&arParms[cParms++], pCurCmd->mContextID); 1163 1164 int rc2 = hostCallback(GUEST_DISCONNECTED, cParms, arParms); 1165 if (RT_FAILURE(rc2)) 1087 LogFlowFunc(("[Client %RU32] Disconnected (%zu clients total)\n", idClient, mClientStateMap.size())); 1088 1089 ClientStateMapIter ItClientState = mClientStateMap.find(idClient); 1090 AssertMsgReturn(ItClientState != mClientStateMap.end(), 1091 ("Client ID=%RU32 not found in client list when it should be there\n", idClient), 1092 VINF_SUCCESS); 1093 1094 /* 1095 * Cancel all pending host commands, replying with GUEST_DISCONNECTED if final recipient. 1096 */ 1097 { 1098 ClientState &rClientState = ItClientState->second; 1099 1100 while (!rClientState.mHostCmdList.empty()) 1101 { 1102 HostCommand *pHostCmd = *rClientState.mHostCmdList.begin(); 1103 rClientState.mHostCmdList.pop_front(); 1104 1105 uint32_t idFunction = pHostCmd->mMsgType; 1106 uint32_t idContext = pHostCmd->m_idContext; 1107 if (pHostCmd->SaneRelease() == 0) 1166 1108 { 1167 LogFlowFunc(("Cancelling host command with CID=%u (refCount=%RU32) failed with rc=%Rrc\n", 1168 pCurCmd->mContextID, pCurCmd->mRefCount, rc2)); 1169 /* Keep going. */ 1109 VBOXHGCMSVCPARM Parm; 1110 HGCMSvcSetU32(&Parm, pHostCmd->m_idContext); 1111 int rc2 = hostCallback(GUEST_DISCONNECTED, 1, &Parm); 1112 LogFlowFunc(("Cancelled host command %u (%s) with idContext=%#x -> %Rrc\n", 1113 idFunction, GstCtrlHostFnName((eHostFn)idFunction), idContext, rc2)); 1114 RT_NOREF(rc2); 1170 1115 } 1171 1172 while (pCurCmd->Release()) 1173 ; 1174 delete pCurCmd; 1175 pCurCmd = NULL; 1176 1177 if (fLast) 1178 break; 1179 1180 pCurCmd = pNext; 1181 } 1182 1183 Assert(RTListIsEmpty(&mHostCmdList)); 1184 } 1185 1186 return rc; 1116 } 1117 } 1118 1119 /* 1120 * Delete the client state. 1121 */ 1122 mClientStateMap.erase(ItClientState); 1123 1124 /* 1125 * If it's the master disconnecting, we need to reset related globals. 1126 */ 1127 if (idClient == m_idMasterClient) 1128 { 1129 m_idMasterClient = UINT32_MAX; 1130 GstCtrlPreparedSession *pCur, *pNext; 1131 RTListForEachSafe(&m_PreparedSessions, pCur, pNext, GstCtrlPreparedSession, ListEntry) 1132 { 1133 RTMemFree(pCur); 1134 } 1135 m_cPreparedSessions = 0; 1136 } 1137 1138 if (mClientStateMap.empty()) 1139 m_fLegacyMode = true; 1140 1141 /* 1142 * Host command sanity check. 1143 */ 1144 Assert(RTListIsEmpty(&mHostCmdList) || !mClientStateMap.empty()); 1145 1146 return VINF_SUCCESS; 1187 1147 } 1148 1188 1149 1189 1150 /** … … 1199 1160 * @param paParms Array of parameters. 1200 1161 */ 1201 int Service::clientMsgOldGet(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle,1202 uint32_t cParms, VBOXHGCMSVCPARM paParms[])1162 int GstCtrlService::clientMsgOldGet(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, 1163 uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 1203 1164 { 1204 1165 /* … … 1229 1190 } 1230 1191 1231 /** 1232 * Implements GUEST_MSG_PEEK_WAIT and GUEST_MSG_PEEK_NOWAIT. 1192 1193 /** 1194 * Implements GUEST_MAKE_ME_MASTER. 1233 1195 * 1234 1196 * @returns VBox status code. 1235 * @retval VINF_ SUCCESS if a message was pending and is being returned.1236 * @retval VERR_ INVALID_HANDLE if invalid client ID.1237 * @retval VERR_ INVALID_PARAMETER if incorrect parameter count or types.1238 * @retval VERR_ TRY_AGAIN if no message pending and not blocking.1239 * @retval VERR_ RESOURCE_BUSY if another read already made a waiting call.1240 * @retval V INF_HGCM_ASYNC_EXECUTE if message wait is pending.1197 * @retval VINF_HGCM_ASYNC_EXECUTE on success (we complete the message here). 1198 * @retval VERR_ACCESS_DENIED if not using main VBoxGuest device not 1199 * @retval VERR_RESOURCE_BUSY if there is already a master. 1200 * @retval VERR_VERSION_MISMATCH if VBoxGuest didn't supply requestor info. 1201 * @retval VERR_INVALID_CLIENT_ID 1202 * @retval VERR_WRONG_PARAMETER_COUNT 1241 1203 * 1242 1204 * @param idClient The client's ID. … … 1247 1209 * immediately. 1248 1210 */ 1249 int Service::clientMsgPeek(uint32_t idClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool fWait)1211 int GstCtrlService::clientMakeMeMaster(uint32_t idClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms) 1250 1212 { 1251 1213 /* 1252 1214 * Validate the request. 1253 1215 */ 1254 ASSERT_GUEST_MSG_RETURN(cParms >= 2, ("cParms=%u!\n", cParms), VERR_INVALID_PARAMETER); 1216 ASSERT_GUEST_RETURN(cParms == 0, VERR_WRONG_PARAMETER_COUNT); 1217 1218 uint32_t fRequestor = mpHelpers->pfnGetRequestor(hCall); 1219 ASSERT_GUEST_LOGREL_MSG_RETURN(fRequestor != VMMDEV_REQUESTOR_LEGACY, 1220 ("Outdated VBoxGuest w/o requestor support. Please update!\n"), 1221 VERR_VERSION_MISMATCH); 1222 ASSERT_GUEST_LOGREL_MSG_RETURN(!(fRequestor & VMMDEV_REQUESTOR_USER_DEVICE), ("fRequestor=%#x\n", fRequestor), 1223 VERR_ACCESS_DENIED); 1224 1225 ClientStateMapIter ItClientState = mClientStateMap.find(idClient); 1226 ASSERT_GUEST_MSG_RETURN(ItClientState != mClientStateMap.end(), ("idClient=%RU32\n", idClient), VERR_INVALID_CLIENT_ID); 1227 ClientState &rClientState = ItClientState->second; 1228 1229 /* 1230 * Do the work. 1231 */ 1232 ASSERT_GUEST_MSG_RETURN(m_idMasterClient == idClient || m_idMasterClient == UINT32_MAX, 1233 ("Already have master session %RU32, refusing %RU32.\n", m_idMasterClient, idClient), 1234 VERR_RESOURCE_BUSY); 1235 int rc = mpHelpers->pfnCallComplete(hCall, VINF_SUCCESS); 1236 if (RT_SUCCESS(rc)) 1237 { 1238 m_idMasterClient = idClient; 1239 m_fLegacyMode = false; 1240 rClientState.m_fIsMaster = true; 1241 } 1242 else 1243 LogFunc(("pfnCallComplete -> %Rrc\n", rc)); 1244 1245 return VINF_HGCM_ASYNC_EXECUTE; 1246 } 1247 1248 /** 1249 * Implements GUEST_MSG_PEEK_WAIT and GUEST_MSG_PEEK_NOWAIT. 1250 * 1251 * @returns VBox status code. 1252 * @retval VINF_SUCCESS if a message was pending and is being returned. 1253 * @retval VERR_TRY_AGAIN if no message pending and not blocking. 1254 * @retval VERR_RESOURCE_BUSY if another read already made a waiting call. 1255 * @retval VINF_HGCM_ASYNC_EXECUTE if message wait is pending. 1256 * 1257 * @param idClient The client's ID. 1258 * @param hCall The client's call handle. 1259 * @param cParms Number of parameters. 1260 * @param paParms Array of parameters. 1261 * @param fWait Set if we should wait for a message, clear if to return 1262 * immediately. 1263 */ 1264 int GstCtrlService::clientMsgPeek(uint32_t idClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool fWait) 1265 { 1266 /* 1267 * Validate the request. 1268 */ 1269 ASSERT_GUEST_MSG_RETURN(cParms >= 2, ("cParms=%u!\n", cParms), VERR_WRONG_PARAMETER_COUNT); 1255 1270 for (uint32_t i = 0; i < cParms; i++) 1256 1271 { 1257 1272 ASSERT_GUEST_MSG_RETURN(paParms[i].type == VBOX_HGCM_SVC_PARM_32BIT, ("#%u type=%u\n", i, paParms[i].type), 1258 VERR_ INVALID_PARAMETER);1273 VERR_WRONG_PARAMETER_TYPE); 1259 1274 paParms[i].u.uint32 = 0; 1260 1275 } 1261 1276 1262 ClientStateMapIter itClientState = mClientStateMap.find(idClient); 1263 ASSERT_GUEST_MSG_RETURN(itClientState != mClientStateMap.end(), ("idClient=%RU32\n", idClient), VERR_INVALID_HANDLE); 1264 1265 ClientState &rClientState = itClientState->second; 1277 ClientStateMapIter ItClientState = mClientStateMap.find(idClient); 1278 ASSERT_GUEST_MSG_RETURN(ItClientState != mClientStateMap.end(), ("idClient=%RU32\n", idClient), VERR_INVALID_CLIENT_ID); 1279 ClientState &rClientState = ItClientState->second; 1266 1280 1267 1281 /* … … 1282 1296 } 1283 1297 1284 LogFlowFunc(("[Client %RU32] GUEST_MSG_PEEK_XXXX -> VINF_SUCCESS (idMsg=%u , cParms=%u)\n",1285 idClient, pFirstCmd->mMsgType, pFirstCmd->mParmCount));1298 LogFlowFunc(("[Client %RU32] GUEST_MSG_PEEK_XXXX -> VINF_SUCCESS (idMsg=%u (%s), cParms=%u)\n", 1299 idClient, pFirstCmd->mMsgType, GstCtrlHostFnName((eHostFn)pFirstCmd->mMsgType), pFirstCmd->mParmCount)); 1286 1300 return VINF_SUCCESS; 1287 1301 } … … 1315 1329 * @retval VERR_TRY_AGAIN if no message pending. 1316 1330 * @retval VERR_BUFFER_OVERFLOW if a parmeter buffer is too small. The buffer 1317 * size was updated to reflect the required size. 1331 * size was updated to reflect the required size, though this isn't yet 1332 * forwarded to the guest. (The guest is better of using peek with 1333 * parameter count + 2 parameters to get the sizes.) 1318 1334 * @retval VERR_MISMATCH if the incoming message ID does not match the pending. 1319 * @retval VERR_OUT_OF_RANGE if the wrong parameter count. 1320 * @retval VERR_WRONG_TYPE if a parameter has the wrong type. 1321 * @retval VERR_INVALID_HANDLE if invalid client ID. 1322 * @retval VINF_HGCM_ASYNC_EXECUTE if message wait is pending. 1335 * @retval VINF_HGCM_ASYNC_EXECUTE if message was completed already. 1323 1336 * 1324 1337 * @param idClient The client's ID. … … 1327 1340 * @param paParms Array of parameters. 1328 1341 */ 1329 int Service::clientMsgGet(uint32_t idClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[])1342 int GstCtrlService::clientMsgGet(uint32_t idClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 1330 1343 { 1331 1344 /* … … 1339 1352 : UINT32_MAX; 1340 1353 1341 ClientStateMapIter itClientState = mClientStateMap.find(idClient);1342 ASSERT_GUEST_MSG_RETURN( itClientState != mClientStateMap.end(), ("idClient=%RU32\n", idClient), VERR_INVALID_HANDLE);1343 1344 ClientState &rClientState = itClientState->second;1354 ClientStateMapIter ItClientState = mClientStateMap.find(idClient); 1355 ASSERT_GUEST_MSG_RETURN(ItClientState != mClientStateMap.end(), ("idClient=%RU32\n", idClient), VERR_INVALID_CLIENT_ID); 1356 1357 ClientState &rClientState = ItClientState->second; 1345 1358 1346 1359 /* … … 1353 1366 1354 1367 ASSERT_GUEST_MSG_RETURN(pFirstCmd->mMsgType == idMsgExpected || idMsgExpected == UINT32_MAX, 1355 ("idMsg=%u cParms=%u, caller expected %u and %u\n", 1356 pFirstCmd->mMsgType, pFirstCmd->mParmCount, idMsgExpected, cParms), 1368 ("idMsg=%u (%s) cParms=%u, caller expected %u (%s) and %u\n", 1369 pFirstCmd->mMsgType, GstCtrlHostFnName((eHostFn)pFirstCmd->mMsgType), pFirstCmd->mParmCount, 1370 idMsgExpected, GstCtrlHostFnName((eHostFn)idMsgExpected), cParms), 1357 1371 VERR_MISMATCH); 1358 1372 ASSERT_GUEST_MSG_RETURN(pFirstCmd->mParmCount == cParms, 1359 ("idMsg=%u cParms=%u, caller expected %u and %u\n", 1360 pFirstCmd->mMsgType, pFirstCmd->mParmCount, idMsgExpected, cParms), 1361 VERR_OUT_OF_RANGE); 1373 ("idMsg=%u (%s) cParms=%u, caller expected %u (%s) and %u\n", 1374 pFirstCmd->mMsgType, GstCtrlHostFnName((eHostFn)pFirstCmd->mMsgType), pFirstCmd->mParmCount, 1375 idMsgExpected, GstCtrlHostFnName((eHostFn)idMsgExpected), cParms), 1376 VERR_WRONG_PARAMETER_COUNT); 1362 1377 1363 1378 /* Check the parameter types. */ 1364 1379 for (uint32_t i = 0; i < cParms; i++) 1365 1380 ASSERT_GUEST_MSG_RETURN(pFirstCmd->mpParms[i].type == paParms[i].type, 1366 ("param #%u: type %u, caller expected %u\n", i, pFirstCmd->mpParms[i].type, paParms[i].type), 1367 VERR_WRONG_TYPE); 1381 ("param #%u: type %u, caller expected %u (idMsg=%u %s)\n", i, pFirstCmd->mpParms[i].type, 1382 paParms[i].type, pFirstCmd->mMsgType, GstCtrlHostFnName((eHostFn)pFirstCmd->mMsgType)), 1383 VERR_WRONG_PARAMETER_TYPE); 1368 1384 1369 1385 /* … … 1414 1430 { 1415 1431 rClientState.mHostCmdList.erase(itFirstCmd); 1416 if (pFirstCmd->Release() == 0) 1417 { 1418 delete pFirstCmd; 1419 LogFlow(("[Client %RU32] Destroying command (idMsg=%u cParms=%u)\n", idClient, idMsgExpected, cParms)); 1420 } 1432 pFirstCmd->SaneRelease(); 1421 1433 } 1434 else 1435 LogFunc(("pfnCallComplete -> %Rrc\n", rc)); 1422 1436 return VINF_HGCM_ASYNC_EXECUTE; /* The caller must not complete it. */ 1423 1437 } … … 1437 1451 * @retval VINF_SUCCESS if cancelled any calls. 1438 1452 * @retval VWRN_NOT_FOUND if no callers. 1439 * @retval VERR_INVALID_PARAMETER if any parameters specified (expects zero).1440 * @retval VERR_INVALID_HANDLE if invalid client ID.1441 1453 * @retval VINF_HGCM_ASYNC_EXECUTE if message wait is pending. 1442 1454 * … … 1444 1456 * @param cParms Number of parameters. 1445 1457 */ 1446 int Service::clientMsgCancel(uint32_t idClient, uint32_t cParms)1458 int GstCtrlService::clientMsgCancel(uint32_t idClient, uint32_t cParms) 1447 1459 { 1448 1460 /* 1449 1461 * Validate the request. 1450 1462 */ 1451 ASSERT_GUEST_MSG_RETURN(cParms == 0, ("cParms=%u!\n", cParms), VERR_ INVALID_PARAMETER);1452 1453 ClientStateMapIter itClientState = mClientStateMap.find(idClient);1454 ASSERT_GUEST_MSG_RETURN( itClientState != mClientStateMap.end(), ("idClient=%RU32\n", idClient), VERR_INVALID_HANDLE);1455 1456 ClientState &rClientState = itClientState->second; 1463 ASSERT_GUEST_MSG_RETURN(cParms == 0, ("cParms=%u!\n", cParms), VERR_WRONG_PARAMETER_COUNT); 1464 1465 ClientStateMapIter ItClientState = mClientStateMap.find(idClient); 1466 ASSERT_GUEST_MSG_RETURN(ItClientState != mClientStateMap.end(), ("idClient=%RU32\n", idClient), VERR_INVALID_CLIENT_ID); 1467 ClientState &rClientState = ItClientState->second; 1468 1457 1469 if (rClientState.mIsPending != 0) 1458 1470 { … … 1465 1477 1466 1478 /** 1467 * A client tells this service to set a message filter. 1468 * That way a client only will get new messages which matches the filter. 1469 * 1470 * @return VBox status code. 1471 * @param u32ClientID The client's ID. 1472 * @param callHandle The client's call handle. 1473 * @param cParms Number of parameters. 1474 * @param paParms Array of parameters. 1475 */ 1476 int Service::clientMsgFilterSet(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, 1477 uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 1478 { 1479 RT_NOREF(callHandle); 1480 1481 /* 1482 * Lookup client in our list so that we can assign the context ID of 1483 * a command to that client. 1484 */ 1485 ClientStateMapIter itClientState = mClientStateMap.find(u32ClientID); 1486 AssertMsg(itClientState != mClientStateMap.end(), ("Client with ID=%RU32 not found when it should be present\n", 1487 u32ClientID)); 1488 if (itClientState == mClientStateMap.end()) 1489 return VERR_NOT_FOUND; /* Should never happen. */ 1490 1491 if (cParms != 4) 1492 return VERR_INVALID_PARAMETER; 1493 1494 uint32_t uValue; 1495 int rc = HGCMSvcGetU32(&paParms[0], &uValue); 1479 * Implements GUEST_MSG_SKIP. 1480 * 1481 * @returns VBox status code. 1482 * @retval VINF_HGCM_ASYNC_EXECUTE on success as we complete the message. 1483 * @retval VERR_NOT_FOUND if no message pending. 1484 * 1485 * @param idClient The client's ID. 1486 * @param hCall The call handle for completing it. 1487 * @param cParms Number of parameters. 1488 */ 1489 int GstCtrlService::clientMsgSkip(uint32_t idClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms) 1490 { 1491 /* 1492 * Validate the call. 1493 */ 1494 ASSERT_GUEST_RETURN(cParms == 0, VERR_WRONG_PARAMETER_COUNT); 1495 1496 ClientStateMapIter ItClientState = mClientStateMap.find(idClient); 1497 ASSERT_GUEST_MSG_RETURN(ItClientState != mClientStateMap.end(), ("idClient=%RU32\n", idClient), VERR_INVALID_CLIENT_ID); 1498 ClientState &rClientState = ItClientState->second; 1499 1500 /* 1501 * Do the job. 1502 */ 1503 if (!rClientState.mHostCmdList.empty()) 1504 { 1505 int rc = mpHelpers->pfnCallComplete(hCall, VERR_NOT_FOUND); 1506 if (RT_SUCCESS(rc)) 1507 { 1508 /* 1509 * Remove the command from the queue. 1510 */ 1511 HostCommand *pFirstCmd = *rClientState.mHostCmdList.begin(); 1512 rClientState.mHostCmdList.pop_front(); 1513 1514 /* 1515 * Compose a reply to the host service. 1516 */ 1517 VBOXHGCMSVCPARM aReplyParams[4]; 1518 HGCMSvcSetU32(&aReplyParams[0], pFirstCmd->m_idContext); 1519 HGCMSvcSetU32(&aReplyParams[1], pFirstCmd->mMsgType); 1520 HGCMSvcSetU32(&aReplyParams[2], (uint32_t)VERR_NOT_SUPPORTED); 1521 HGCMSvcSetPv(&aReplyParams[3], NULL, 0); 1522 GstCtrlService::hostCallback(GUEST_MSG_REPLY, RT_ELEMENTS(aReplyParams), aReplyParams); 1523 1524 /* 1525 * Free the command. 1526 */ 1527 pFirstCmd->SaneRelease(); 1528 } 1529 else 1530 LogFunc(("pfnCallComplete -> %Rrc\n", rc)); 1531 return VINF_HGCM_ASYNC_EXECUTE; /* The caller must not complete it. */ 1532 } 1533 return VERR_NOT_FOUND; 1534 } 1535 1536 1537 /** 1538 * Implements GUEST_SESSION_PREPARE. 1539 * 1540 * @returns VBox status code. 1541 * @retval VINF_HGCM_ASYNC_EXECUTE on success as we complete the message. 1542 * @retval VERR_OUT_OF_RESOURCES if too many pending sessions hanging around. 1543 * @retval VERR_OUT_OF_RANGE if the session ID outside the allowed range. 1544 * @retval VERR_BUFFER_OVERFLOW if key too large. 1545 * @retval VERR_BUFFER_UNDERFLOW if key too small. 1546 * @retval VERR_ACCESS_DENIED if not master or in legacy mode. 1547 * @retval VERR_DUPLICATE if the session ID has been prepared already. 1548 * 1549 * @param idClient The client's ID. 1550 * @param hCall The call handle for completing it. 1551 * @param cParms Number of parameters. 1552 * @param paParms The parameters. 1553 */ 1554 int GstCtrlService::clientSessionPrepare(uint32_t idClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 1555 { 1556 /* 1557 * Validate parameters. 1558 */ 1559 ASSERT_GUEST_RETURN(cParms == 2, VERR_WRONG_PARAMETER_COUNT); 1560 ASSERT_GUEST_RETURN(paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE); 1561 uint32_t const idSession = paParms[0].u.uint32; 1562 ASSERT_GUEST_RETURN(idSession >= 1, VERR_OUT_OF_RANGE); 1563 ASSERT_GUEST_RETURN(idSession <= 0xfff0, VERR_OUT_OF_RANGE); 1564 1565 ASSERT_GUEST_RETURN(paParms[1].type == VBOX_HGCM_SVC_PARM_PTR, VERR_WRONG_PARAMETER_TYPE); 1566 uint32_t const cbKey = paParms[1].u.pointer.size; 1567 void const *pvKey = paParms[1].u.pointer.addr; 1568 ASSERT_GUEST_RETURN(cbKey >= 64, VERR_BUFFER_UNDERFLOW); 1569 ASSERT_GUEST_RETURN(cbKey <= _16K, VERR_BUFFER_OVERFLOW); 1570 1571 ClientStateMapIter ItClientState = mClientStateMap.find(idClient); 1572 ASSERT_GUEST_MSG_RETURN(ItClientState != mClientStateMap.end(), ("idClient=%RU32\n", idClient), VERR_INVALID_CLIENT_ID); 1573 ClientState &rClientState = ItClientState->second; 1574 ASSERT_GUEST_RETURN(rClientState.m_fIsMaster, VERR_ACCESS_DENIED); 1575 ASSERT_GUEST_RETURN(!m_fLegacyMode, VERR_ACCESS_DENIED); 1576 Assert(m_idMasterClient == idClient); 1577 1578 /* Now that we know it's the master, we can check for session ID duplicates. */ 1579 GstCtrlPreparedSession *pCur; 1580 RTListForEach(&m_PreparedSessions, pCur, GstCtrlPreparedSession, ListEntry) 1581 { 1582 ASSERT_GUEST_RETURN(pCur->idSession != idSession, VERR_DUPLICATE); 1583 } 1584 1585 /* 1586 * Make a copy of the session ID and key. 1587 */ 1588 ASSERT_GUEST_RETURN(m_cPreparedSessions < 128, VERR_OUT_OF_RESOURCES); 1589 1590 GstCtrlPreparedSession *pPrepped = (GstCtrlPreparedSession *)RTMemAlloc(RT_UOFFSETOF_DYN(GstCtrlPreparedSession, abKey[cbKey])); 1591 AssertReturn(pPrepped, VERR_NO_MEMORY); 1592 pPrepped->idSession = idSession; 1593 pPrepped->cbKey = cbKey; 1594 memcpy(pPrepped->abKey, pvKey, cbKey); 1595 1596 RTListAppend(&m_PreparedSessions, &pPrepped->ListEntry); 1597 m_cPreparedSessions++; 1598 1599 /* 1600 * Try complete the command. 1601 */ 1602 int rc = mpHelpers->pfnCallComplete(hCall, VERR_NOT_FOUND); 1496 1603 if (RT_SUCCESS(rc)) 1497 { 1498 uint32_t uMaskAdd; 1499 rc = HGCMSvcGetU32(&paParms[1], &uMaskAdd); 1500 if (RT_SUCCESS(rc)) 1501 { 1502 uint32_t uMaskRemove; 1503 rc = HGCMSvcGetU32(&paParms[2], &uMaskRemove); 1504 /** @todo paParm[3] (flags) not used yet. */ 1505 if (RT_SUCCESS(rc)) 1604 LogFlow(("Prepared %u with a %#x byte key (%u pending).\n", idSession, cbKey, m_cPreparedSessions)); 1605 else 1606 { 1607 LogFunc(("pfnCallComplete -> %Rrc\n", rc)); 1608 RTListNodeRemove(&pPrepped->ListEntry); 1609 RTMemFree(pPrepped); 1610 m_cPreparedSessions--; 1611 } 1612 return VINF_HGCM_ASYNC_EXECUTE; /* The caller must not complete it. */ 1613 } 1614 1615 1616 /** 1617 * Implements GUEST_SESSION_CANCEL_PREPARED. 1618 * 1619 * @returns VBox status code. 1620 * @retval VINF_HGCM_ASYNC_EXECUTE on success as we complete the message. 1621 * @retval VWRN_NOT_FOUND if no session with the specified ID. 1622 * @retval VERR_ACCESS_DENIED if not master or in legacy mode. 1623 * 1624 * @param idClient The client's ID. 1625 * @param cParms Number of parameters. 1626 * @param paParms The parameters. 1627 */ 1628 int GstCtrlService::clientSessionCancelPrepared(uint32_t idClient, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 1629 { 1630 /* 1631 * Validate parameters. 1632 */ 1633 ASSERT_GUEST_RETURN(cParms == 1, VERR_WRONG_PARAMETER_COUNT); 1634 ASSERT_GUEST_RETURN(paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE); 1635 uint32_t const idSession = paParms[0].u.uint32; 1636 1637 ClientStateMapIter ItClientState = mClientStateMap.find(idClient); 1638 ASSERT_GUEST_MSG_RETURN(ItClientState != mClientStateMap.end(), ("idClient=%RU32\n", idClient), VERR_INVALID_CLIENT_ID); 1639 ClientState &rClientState = ItClientState->second; 1640 ASSERT_GUEST_RETURN(rClientState.m_fIsMaster, VERR_ACCESS_DENIED); 1641 ASSERT_GUEST_RETURN(!m_fLegacyMode, VERR_ACCESS_DENIED); 1642 Assert(m_idMasterClient == idClient); 1643 1644 /* 1645 * Do the work. 1646 */ 1647 int rc = VWRN_NOT_FOUND; 1648 if (idSession == UINT32_MAX) 1649 { 1650 GstCtrlPreparedSession *pCur, *pNext; 1651 RTListForEachSafe(&m_PreparedSessions, pCur, pNext, GstCtrlPreparedSession, ListEntry) 1652 { 1653 RTMemFree(pCur); 1654 rc = VINF_SUCCESS; 1655 } 1656 m_cPreparedSessions = 0; 1657 } 1658 else 1659 { 1660 GstCtrlPreparedSession *pCur, *pNext; 1661 RTListForEachSafe(&m_PreparedSessions, pCur, pNext, GstCtrlPreparedSession, ListEntry) 1662 { 1663 if (pCur->idSession == idSession) 1506 1664 { 1507 ClientState &clientState = itClientState->second; 1508 1509 clientState.mFlags |= CLIENTSTATE_FLAG_CONTEXTFILTER; 1510 if (uMaskAdd) 1511 clientState.mFilterMask |= uMaskAdd; 1512 if (uMaskRemove) 1513 clientState.mFilterMask &= ~uMaskRemove; 1514 1515 clientState.mFilterValue = uValue; 1516 1517 LogFlowFunc(("[Client %RU32] Setting message filterMask=0x%x, filterVal=%RU32 set (flags=0x%x, maskAdd=0x%x, maskRemove=0x%x)\n", 1518 u32ClientID, clientState.mFilterMask, clientState.mFilterValue, 1519 clientState.mFlags, uMaskAdd, uMaskRemove)); 1665 RTMemFree(pCur); 1666 m_cPreparedSessions -= 1; 1667 rc = VINF_SUCCESS; 1668 break; 1520 1669 } 1521 1670 } 1522 1671 } 1523 1672 return VINF_SUCCESS; 1673 } 1674 1675 1676 /** 1677 * Implements GUEST_SESSION_ACCEPT. 1678 * 1679 * @returns VBox status code. 1680 * @retval VINF_HGCM_ASYNC_EXECUTE on success as we complete the message. 1681 * @retval VERR_NOT_FOUND if the specified session ID wasn't found. 1682 * @retval VERR_MISMATCH if the key didn't match. 1683 * @retval VERR_ACCESS_DENIED if we're in legacy mode or is master. 1684 * @retval VERR_RESOURCE_BUSY if the client is already associated with a 1685 * session. 1686 * 1687 * @param idClient The client's ID. 1688 * @param hCall The call handle for completing it. 1689 * @param cParms Number of parameters. 1690 * @param paParms The parameters. 1691 */ 1692 int GstCtrlService::clientSessionAccept(uint32_t idClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 1693 { 1694 /* 1695 * Validate parameters. 1696 */ 1697 ASSERT_GUEST_RETURN(cParms == 2, VERR_WRONG_PARAMETER_COUNT); 1698 ASSERT_GUEST_RETURN(paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE); 1699 uint32_t const idSession = paParms[0].u.uint32; 1700 ASSERT_GUEST_RETURN(idSession >= 1, VERR_OUT_OF_RANGE); 1701 ASSERT_GUEST_RETURN(idSession <= 0xfff0, VERR_OUT_OF_RANGE); 1702 1703 ASSERT_GUEST_RETURN(paParms[1].type == VBOX_HGCM_SVC_PARM_PTR, VERR_WRONG_PARAMETER_TYPE); 1704 uint32_t const cbKey = paParms[1].u.pointer.size; 1705 void const *pvKey = paParms[1].u.pointer.addr; 1706 ASSERT_GUEST_RETURN(cbKey >= 64, VERR_BUFFER_UNDERFLOW); 1707 ASSERT_GUEST_RETURN(cbKey <= _16K, VERR_BUFFER_OVERFLOW); 1708 1709 ClientStateMapIter ItClientState = mClientStateMap.find(idClient); 1710 ASSERT_GUEST_MSG_RETURN(ItClientState != mClientStateMap.end(), ("idClient=%RU32\n", idClient), VERR_INVALID_CLIENT_ID); 1711 ClientState &rClientState = ItClientState->second; 1712 ASSERT_GUEST_RETURN(!rClientState.m_fIsMaster, VERR_ACCESS_DENIED); 1713 ASSERT_GUEST_RETURN(!m_fLegacyMode, VERR_ACCESS_DENIED); 1714 Assert(m_idMasterClient != idClient); 1715 ASSERT_GUEST_RETURN(rClientState.m_idSession == UINT32_MAX, VERR_RESOURCE_BUSY); 1716 1717 /* 1718 * Look for the specified session and match the key to it. 1719 */ 1720 GstCtrlPreparedSession *pCur; 1721 RTListForEach(&m_PreparedSessions, pCur, GstCtrlPreparedSession, ListEntry) 1722 { 1723 if (pCur->idSession == idSession) 1724 { 1725 if ( pCur->cbKey == cbKey 1726 && memcmp(pCur->abKey, pvKey, cbKey) == 0) 1727 { 1728 /* 1729 * We've got a match. Try complete the request and 1730 */ 1731 int rc = mpHelpers->pfnCallComplete(hCall, VERR_NOT_FOUND); 1732 if (RT_SUCCESS(rc)) 1733 { 1734 rClientState.m_idSession = idSession; 1735 1736 RTMemFree(pCur); 1737 m_cPreparedSessions -= 1; 1738 } 1739 else 1740 LogFunc(("pfnCallComplete -> %Rrc\n", rc)); 1741 return VINF_HGCM_ASYNC_EXECUTE; /* The caller must not complete it. */ 1742 } 1743 LogFunc(("Key mismatch for %u!\n", idClient)); 1744 return VERR_MISMATCH; 1745 } 1746 } 1747 1748 LogFunc(("No client prepared for %u!\n", idClient)); 1749 return VERR_NOT_FOUND; 1750 } 1751 1752 1753 /** 1754 * Client asks another client (guest) session to close. 1755 * 1756 * @return IPRT status code. 1757 * @param idClient The client's ID. 1758 * @param cParms Number of parameters. 1759 * @param paParms Array of parameters. 1760 */ 1761 int GstCtrlService::clientSessionCloseOther(uint32_t idClient, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 1762 { 1763 /* 1764 * Validate input. 1765 */ 1766 ASSERT_GUEST_RETURN(cParms == 2, VERR_WRONG_PARAMETER_COUNT); 1767 ASSERT_GUEST_RETURN(paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE); 1768 uint32_t const idContext = paParms[0].u.uint32; 1769 1770 ASSERT_GUEST_RETURN(paParms[1].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE); 1771 uint32_t const fFlags = paParms[1].u.uint32; 1772 1773 ClientStateMapIter ItClientState = mClientStateMap.find(idClient); 1774 ASSERT_GUEST_MSG_RETURN(ItClientState != mClientStateMap.end(), ("idClient=%RU32\n", idClient), VERR_INVALID_CLIENT_ID); 1775 ClientState &rClientState = ItClientState->second; 1776 ASSERT_GUEST_RETURN(rClientState.m_fIsMaster, VERR_ACCESS_DENIED); 1777 1778 /* 1779 * Forward the command to the destiation. 1780 * Since we modify the first parameter, we must make a copy of the parameters. 1781 */ 1782 VBOXHGCMSVCPARM aParms[2]; 1783 HGCMSvcSetU64(&aParms[0], idContext | VBOX_GUESTCTRL_DST_SESSION); 1784 HGCMSvcSetU32(&aParms[1], fFlags); 1785 int rc = hostProcessCommand(HOST_SESSION_CLOSE, RT_ELEMENTS(aParms), aParms); 1786 1787 LogFlowFunc(("Closing guest context ID=%RU32 (from client ID=%RU32) returned with rc=%Rrc\n", idContext, idClient, rc)); 1524 1788 return rc; 1525 1789 } 1526 1790 1527 /** 1528 * A client tells this service to unset (clear) its message filter. 1791 1792 /** 1793 * For compatiblity with old additions only - filtering / set session ID. 1529 1794 * 1530 1795 * @return VBox status code. 1531 * @param u32ClientID The client's ID. 1532 * @param callHandle The client's call handle. 1533 * @param cParms Number of parameters. 1534 * @param paParms Array of parameters. 1535 */ 1536 int Service::clientMsgFilterUnset(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, 1537 uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 1538 { 1539 RT_NOREF(callHandle, paParms); 1540 1541 /* 1542 * Lookup client in our list so that we can assign the context ID of 1543 * a command to that client. 1544 */ 1545 ClientStateMapIter itClientState = mClientStateMap.find(u32ClientID); 1546 AssertMsg(itClientState != mClientStateMap.end(), ("Client with ID=%RU32 not found when it should be present\n", 1547 u32ClientID)); 1548 if (itClientState == mClientStateMap.end()) 1549 return VERR_NOT_FOUND; /* Should never happen. */ 1550 1551 if (cParms != 1) 1552 return VERR_INVALID_PARAMETER; 1553 1554 ClientState &clientState = itClientState->second; 1555 1556 clientState.mFlags &= ~CLIENTSTATE_FLAG_CONTEXTFILTER; 1557 clientState.mFilterMask = 0; 1558 clientState.mFilterValue = 0; 1559 1560 LogFlowFunc(("[Client %RU32} Unset message filter\n", u32ClientID)); 1796 * @param idClient The client's HGCM ID. 1797 * @param cParms Number of parameters. 1798 * @param paParms Array of parameters. 1799 */ 1800 int GstCtrlService::clientMsgOldFilterSet(uint32_t idClient, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 1801 { 1802 /* 1803 * Validate input and access. 1804 */ 1805 ASSERT_GUEST_RETURN(cParms == 4, VERR_WRONG_PARAMETER_COUNT); 1806 ASSERT_GUEST_RETURN(paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE); 1807 uint32_t uValue = paParms[0].u.uint32; 1808 ASSERT_GUEST_RETURN(paParms[1].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE); 1809 uint32_t fMaskAdd = paParms[1].u.uint32; 1810 ASSERT_GUEST_RETURN(paParms[2].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE); 1811 uint32_t fMaskRemove = paParms[2].u.uint32; 1812 ASSERT_GUEST_RETURN(paParms[3].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE); /* flags, unused */ 1813 1814 ClientStateMapIter ItClientState = mClientStateMap.find(idClient); 1815 ASSERT_GUEST_MSG_RETURN(ItClientState != mClientStateMap.end(), ("idClient=%RU32\n", idClient), VERR_INVALID_CLIENT_ID); 1816 ClientState &rClientState = ItClientState->second; 1817 1818 /* 1819 * We have a bunch of expectations here: 1820 * - Never called in non-legacy mode. 1821 * - Only called once per session. 1822 * - Never called by the master session. 1823 * - Clients that doesn't wish for any messages passes all zeros. 1824 * - All other calls has a unique session ID. 1825 */ 1826 ASSERT_GUEST_LOGREL_RETURN(m_fLegacyMode, VERR_WRONG_ORDER); 1827 ASSERT_GUEST_LOGREL_MSG_RETURN(rClientState.m_idSession == UINT32_MAX, ("m_idSession=%#x\n", rClientState.m_idSession), 1828 VERR_WRONG_ORDER); 1829 ASSERT_GUEST_LOGREL_RETURN(!rClientState.m_fIsMaster, VERR_WRONG_ORDER); 1830 1831 if (uValue == 0) 1832 { 1833 ASSERT_GUEST_LOGREL(fMaskAdd == 0); 1834 ASSERT_GUEST_LOGREL(fMaskRemove == 0); 1835 /* Nothing to do, already muted (UINT32_MAX). */ 1836 } 1837 else 1838 { 1839 ASSERT_GUEST_LOGREL(fMaskAdd == UINT32_C(0xf8000000)); 1840 ASSERT_GUEST_LOGREL(fMaskRemove == 0); 1841 1842 uint32_t idSession = VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(uValue); 1843 ASSERT_GUEST_LOGREL_MSG_RETURN(idSession > 0, ("idSession=%u (%#x)\n", idSession, uValue), VERR_OUT_OF_RANGE); 1844 1845 for (ClientStateMapIter It = mClientStateMap.begin(); It != mClientStateMap.end(); ++It) 1846 ASSERT_GUEST_LOGREL_MSG_RETURN(It->second.m_idSession != idSession, 1847 ("idSession=%u uValue=%#x idClient=%u; conflicting with client %u\n", 1848 idSession, uValue, idClient, It->second.mID), 1849 VERR_DUPLICATE); 1850 /* Commit it. */ 1851 rClientState.m_idSession = idSession; 1852 } 1561 1853 return VINF_SUCCESS; 1562 1854 } 1563 1855 1564 /** 1565 * A client tells this service that the current command can be skipped and therefore can be removed 1566 * from the internal command list. 1856 1857 /** 1858 * For compatibility with old additions only - skip the current command w/o 1859 * calling main code. 1860 * 1861 * Please note that we don't care if the caller cancelled the request, because 1862 * old additions code didn't give damn about VERR_INTERRUPT. 1567 1863 * 1568 1864 * @return VBox status code. 1569 * @param u32ClientID The client's ID. 1570 * @param callHandle The client's call handle. 1571 * @param cParms Number of parameters. 1572 * @param paParms Array of parameters. 1573 */ 1574 int Service::clientMsgSkip(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, 1575 uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 1576 { 1577 RT_NOREF(callHandle, cParms, paParms); 1578 1579 int rc; 1580 1581 /* 1582 * Lookup client in our list so that we can assign the context ID of 1583 * a command to that client. 1584 */ 1585 ClientStateMapIter itClientState = mClientStateMap.find(u32ClientID); 1586 AssertMsg(itClientState != mClientStateMap.end(), ("Client ID=%RU32 not found when it should be present\n", u32ClientID)); 1587 if (itClientState != mClientStateMap.end()) 1588 { 1589 itClientState->second.DequeueCurrent(); 1590 rc = VINF_SUCCESS; 1591 } 1592 else 1593 rc = VERR_NOT_FOUND; 1594 1595 LogFlowFunc(("[Client %RU32] Skipped current message, rc=%Rrc\n", u32ClientID, rc)); 1596 return rc; 1865 * @param idClient The client's HGCM ID. 1866 * @param cParms Number of parameters. 1867 */ 1868 int GstCtrlService::clientMsgOldSkip(uint32_t idClient, uint32_t cParms) 1869 { 1870 /* 1871 * Validate input and access. 1872 */ 1873 ASSERT_GUEST_RETURN(cParms == 1, VERR_WRONG_PARAMETER_COUNT); 1874 1875 ClientStateMapIter ItClientState = mClientStateMap.find(idClient); 1876 ASSERT_GUEST_MSG_RETURN(ItClientState != mClientStateMap.end(), ("idClient=%RU32\n", idClient), VERR_INVALID_CLIENT_ID); 1877 ClientState &rClientState = ItClientState->second; 1878 1879 /* 1880 * Execute the request. 1881 */ 1882 if (!rClientState.mHostCmdList.empty()) 1883 rClientState.DitchFirstHostCmd(); 1884 1885 LogFlowFunc(("[Client %RU32] Skipped current message - leagcy function\n", idClient)); 1886 return VINF_SUCCESS; 1597 1887 } 1888 1598 1889 1599 1890 /** … … 1606 1897 * @param paParms Array of parameters. 1607 1898 */ 1608 int Service::hostCallback(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[])1899 int GstCtrlService::hostCallback(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 1609 1900 { 1610 1901 LogFlowFunc(("eFunction=%ld, cParms=%ld, paParms=%p\n", … … 1615 1906 { 1616 1907 VBOXGUESTCTRLHOSTCALLBACK data(cParms, paParms); 1617 rc = mpfnHostCallback(mpvHostData, eFunction, (void *)(&data), sizeof(data)); 1908 /** @todo Not sure if this try/catch is necessary, I pushed it down here from 1909 * GstCtrlService::call where it was not needed for anything else that I 1910 * could spot. I know this might be a tough, but I expect someone writing 1911 * this kind of code to know what can throw errors and handle them where it 1912 * is appropriate, rather than grand catch-all-at-the-top crap like this. 1913 * The reason why it is utter crap, is that you have no state cleanup code 1914 * where you might need it, which is why I despise exceptions in general */ 1915 try 1916 { 1917 rc = mpfnHostCallback(mpvHostData, eFunction, (void *)(&data), sizeof(data)); 1918 } 1919 catch (std::bad_alloc &) 1920 { 1921 rc = VERR_NO_MEMORY; 1922 } 1618 1923 } 1619 1924 else … … 1624 1929 } 1625 1930 1931 1626 1932 /** 1627 1933 * Processes a command received from the host side and re-routes it to … … 1629 1935 * 1630 1936 * @return IPRT status code. 1631 * @param eFunctionFunction code to process.1632 * @param cParms Number of parameters.1633 * @param paParms Array of parameters.1634 */ 1635 int Service::hostProcessCommand(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[])1937 * @param idFunction Function code to process. 1938 * @param cParms Number of parameters. 1939 * @param paParms Array of parameters. 1940 */ 1941 int GstCtrlService::hostProcessCommand(uint32_t idFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 1636 1942 { 1637 1943 /* … … 1642 1948 */ 1643 1949 if (mClientStateMap.empty()) 1950 { 1951 LogFlow(("GstCtrlService::hostProcessCommand: VERR_NOT_FOUND!\n")); 1644 1952 return VERR_NOT_FOUND; 1645 1646 int rc; 1647 1648 HostCommand *pHostCmd = NULL; 1649 try 1650 { 1651 pHostCmd = new HostCommand(); 1652 rc = pHostCmd->Allocate(eFunction, cParms, paParms); 1653 if (RT_SUCCESS(rc)) 1654 /* rc = */ RTListAppend(&mHostCmdList, &pHostCmd->Node); 1655 } 1656 catch (std::bad_alloc &) 1657 { 1658 rc = VERR_NO_MEMORY; 1659 } 1660 1953 } 1954 1955 HostCommand *pHostCmd = new (std::nothrow) HostCommand(); 1956 AssertReturn(pHostCmd, VERR_NO_MEMORY); 1957 1958 int rc = pHostCmd->Init(idFunction, cParms, paParms); 1661 1959 if (RT_SUCCESS(rc)) 1662 1960 { 1663 LogFlowFunc(("Handling host command CID=%RU32, eFunction=%RU32, cParms=%RU32, paParms=%p, numClients=%zu\n", 1664 pHostCmd->mContextID, eFunction, cParms, paParms, mClientStateMap.size())); 1961 RTListAppend(&mHostCmdList, &pHostCmd->m_ListEntry); 1962 LogFlowFunc(("Handling host command m_idContextAndDst=%#RX64, idFunction=%RU32, cParms=%RU32, paParms=%p, cClients=%zu\n", 1963 pHostCmd->m_idContextAndDst, idFunction, cParms, paParms, mClientStateMap.size())); 1665 1964 1666 1965 /* 1667 * Wake up all pending clients which are interested in this1668 * host command.1966 * Find the message destination and post it to the client. If the 1967 * session ID doesn't match any particular client it goes to the master. 1669 1968 */ 1670 #ifdef DEBUG 1671 uint32_t uClientsWokenUp = 0; 1672 #endif 1673 ClientStateMapIter itClientState = mClientStateMap.begin(); 1674 AssertMsg(itClientState != mClientStateMap.end(), ("Client state map is empty when it should not\n")); 1675 while (itClientState != mClientStateMap.end()) 1676 { 1677 ClientState &clientState = itClientState->second; 1678 1679 /* If a client indicates that it it wants the new host command, 1680 * add a reference to not delete it.*/ 1681 if (clientState.WantsHostCommand(pHostCmd)) 1969 AssertMsg(!mClientStateMap.empty(), ("Client state map is empty when it should not be!\n")); 1970 1971 /* Dispatch to the session. */ 1972 if (pHostCmd->m_idContextAndDst & VBOX_GUESTCTRL_DST_SESSION) 1973 { 1974 rc = VWRN_NOT_FOUND; 1975 uint32_t const idSession = VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(pHostCmd->m_idContext); 1976 for (ClientStateMapIter It = mClientStateMap.begin(); It != mClientStateMap.end(); ++It) 1682 1977 { 1683 clientState.EnqueueCommand(pHostCmd); 1684 1685 int rc2 = clientState.Wakeup(); 1686 if (RT_FAILURE(rc2)) 1687 LogFlowFunc(("Waking up client ID=%RU32 failed with rc=%Rrc\n", 1688 itClientState->first, rc2)); 1689 #ifdef DEBUG 1690 uClientsWokenUp++; 1691 #endif 1692 /** @todo r=bird: Do we need to queue commands on more than one client? */ 1978 ClientState &rClientState = It->second; 1979 if (rClientState.m_idSession == idSession) 1980 { 1981 rc = rClientState.EnqueueCommand(pHostCmd); 1982 if (RT_SUCCESS(rc)) 1983 { 1984 int rc2 = rClientState.Wakeup(); 1985 LogFlowFunc(("Woke up client ID=%RU32 -> rc=%Rrc\n", rClientState.mID, rc2)); 1986 } 1987 break; 1988 } 1693 1989 } 1694 1695 ++itClientState; 1696 } 1697 1698 #ifdef DEBUG 1699 LogFlowFunc(("%RU32 clients have been woken up\n", uClientsWokenUp)); 1700 #endif 1701 } 1702 /** @todo r=bird: If pHostCmd->Allocate fails, you leak stuff. It's not 1703 * likely, since it'll only fail if the host gives us an incorrect 1704 * parameter list (first param isn't uint32_t) or we're out of memory. 1705 * In the latter case, of course, you're not exactly helping... */ 1706 1990 } 1991 1992 /* Does the message go to the root service? */ 1993 if ( (pHostCmd->m_idContextAndDst & VBOX_GUESTCTRL_DST_ROOT_SVC) 1994 && RT_SUCCESS(rc)) 1995 { 1996 ClientStateMapIter It = mClientStateMap.find(m_idMasterClient); 1997 if (It != mClientStateMap.end()) 1998 { 1999 ClientState &rClientState = It->second; 2000 int rc2 = rClientState.EnqueueCommand(pHostCmd); 2001 if (RT_SUCCESS(rc2)) 2002 { 2003 rc2 = rClientState.Wakeup(); 2004 LogFlowFunc(("Woke up client ID=%RU32 (master) -> rc=%Rrc\n", rClientState.mID, rc2)); 2005 } 2006 else 2007 rc = rc2; 2008 } 2009 else 2010 rc = VERR_NOT_FOUND; 2011 } 2012 } 2013 2014 /* Drop our command reference. */ 2015 pHostCmd->SaneRelease(); 2016 2017 if (RT_FAILURE(rc)) 2018 LogFunc(("Failed %Rrc (idFunction=%u, cParms=%u)\n", rc, idFunction, cParms)); 1707 2019 return rc; 1708 2020 } 2021 1709 2022 1710 2023 /** … … 1717 2030 * @thread HGCM 1718 2031 */ 1719 void Service::call(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, 1720 void * /* pvClient */, uint32_t eFunction, uint32_t cParms, 1721 VBOXHGCMSVCPARM paParms[]) 1722 { 1723 int rc = VINF_SUCCESS; 1724 LogFlowFunc(("[Client %RU32] eFunction=%RU32, cParms=%RU32, paParms=0x%p\n", 1725 u32ClientID, eFunction, cParms, paParms)); 1726 try 1727 { 2032 void GstCtrlService::call(VBOXHGCMCALLHANDLE hCall, uint32_t idClient, void * /* pvClient */, uint32_t idFunction, 2033 uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 2034 { 2035 LogFlowFunc(("[Client %RU32] idFunction=%RU32 (%s), cParms=%RU32, paParms=0x%p\n", 2036 idClient, idFunction, GstCtrlHostFnName((eHostFn)idFunction), cParms, paParms)); 2037 int rc; 2038 switch (idFunction) 2039 { 2040 case GUEST_MAKE_ME_MASTER: 2041 LogFlowFunc(("[Client %RU32] GUEST_MAKE_ME_MASTER\n", idClient)); 2042 rc = clientMakeMeMaster(idClient, hCall, cParms); 2043 break; 2044 case GUEST_MSG_PEEK_NOWAIT: 2045 LogFlowFunc(("[Client %RU32] GUEST_MSG_PEEK_NOWAIT\n", idClient)); 2046 rc = clientMsgPeek(idClient, hCall, cParms, paParms, false /*fWait*/); 2047 break; 2048 case GUEST_MSG_PEEK_WAIT: 2049 LogFlowFunc(("[Client %RU32] GUEST_MSG_PEEK_WAIT\n", idClient)); 2050 rc = clientMsgPeek(idClient, hCall, cParms, paParms, true /*fWait*/); 2051 break; 2052 case GUEST_MSG_GET: 2053 LogFlowFunc(("[Client %RU32] GUEST_MSG_GET\n", idClient)); 2054 rc = clientMsgGet(idClient, hCall, cParms, paParms); 2055 break; 2056 case GUEST_MSG_CANCEL: 2057 LogFlowFunc(("[Client %RU32] GUEST_MSG_CANCEL\n", idClient)); 2058 rc = clientMsgCancel(idClient, cParms); 2059 break; 2060 case GUEST_MSG_SKIP: 2061 LogFlowFunc(("[Client %RU32] GUEST_MSG_SKIP\n", idClient)); 2062 rc = clientMsgSkip(idClient, hCall, cParms); 2063 break; 2064 case GUEST_SESSION_PREPARE: 2065 LogFlowFunc(("[Client %RU32] GUEST_SESSION_PREPARE\n", idClient)); 2066 rc = clientSessionPrepare(idClient, hCall, cParms, paParms); 2067 break; 2068 case GUEST_SESSION_CANCEL_PREPARED: 2069 LogFlowFunc(("[Client %RU32] GUEST_SESSION_CANCEL_PREPARED\n", idClient)); 2070 rc = clientSessionCancelPrepared(idClient, cParms, paParms); 2071 break; 2072 case GUEST_SESSION_ACCEPT: 2073 LogFlowFunc(("[Client %RU32] GUEST_SESSION_ACCEPT\n", idClient)); 2074 rc = clientSessionAccept(idClient, hCall, cParms, paParms); 2075 break; 2076 case GUEST_SESSION_CLOSE: 2077 LogFlowFunc(("[Client %RU32] GUEST_SESSION_CLOSE\n", idClient)); 2078 rc = clientSessionCloseOther(idClient, cParms, paParms); 2079 break; 2080 1728 2081 /* 1729 * The guest asks the host for the next message to process. 2082 * For all other regular commands we call our hostCallback 2083 * function. If the current command does not support notifications, 2084 * notifyHost will return VERR_NOT_SUPPORTED. 1730 2085 */ 1731 if (eFunction == GUEST_MSG_WAIT) 1732 { 1733 LogFlowFunc(("[Client %RU32] GUEST_MSG_WAIT\n", u32ClientID)); 1734 rc = clientMsgOldGet(u32ClientID, callHandle, cParms, paParms); 1735 } 1736 else 1737 { 1738 switch (eFunction) 1739 { 1740 /* 1741 * A client wants to shut down and asks us (this service) to cancel 1742 * all blocking/pending waits (VINF_HGCM_ASYNC_EXECUTE) so that the 1743 * client can gracefully shut down. 1744 */ 1745 case GUEST_CANCEL_PENDING_WAITS: 1746 { 1747 LogFlowFunc(("[Client %RU32] GUEST_CANCEL_PENDING_WAITS\n", u32ClientID)); 1748 ClientStateMapIter itClientState = mClientStateMap.find(u32ClientID); 1749 if (itClientState != mClientStateMap.end()) 1750 rc = itClientState->second.CancelWaiting(); 1751 break; 1752 } 1753 1754 /* 1755 * The guest only wants certain messages set by the filter mask(s). 1756 * Since VBox 4.3+. 1757 */ 1758 case GUEST_MSG_FILTER_SET: 1759 LogFlowFunc(("[Client %RU32] GUEST_MSG_FILTER_SET\n", u32ClientID)); 1760 rc = clientMsgFilterSet(u32ClientID, callHandle, cParms, paParms); 1761 break; 1762 1763 /* 1764 * Unsetting the message filter flag. 1765 */ 1766 case GUEST_MSG_FILTER_UNSET: 1767 LogFlowFunc(("[Client %RU32] GUEST_MSG_FILTER_UNSET\n", u32ClientID)); 1768 rc = clientMsgFilterUnset(u32ClientID, callHandle, cParms, paParms); 1769 break; 1770 1771 /* 1772 * The guest only wants skip the currently assigned messages. Neded 1773 * for dropping its assigned reference of the current assigned host 1774 * command in queue. 1775 * Since VBox 4.3+. 1776 */ 1777 case GUEST_MSG_SKIP: 1778 LogFlowFunc(("[Client %RU32] GUEST_MSG_SKIP\n", u32ClientID)); 1779 rc = clientMsgSkip(u32ClientID, callHandle, cParms, paParms); 1780 break; 1781 1782 /* 1783 * New message peeking and retrieval functions replacing GUEST_MSG_WAIT. 1784 */ 1785 case GUEST_MSG_PEEK_NOWAIT: 1786 LogFlowFunc(("[Client %RU32] GUEST_MSG_PEEK_NOWAIT\n", u32ClientID)); 1787 rc = clientMsgPeek(u32ClientID, callHandle, cParms, paParms, false /*fWait*/); 1788 break; 1789 case GUEST_MSG_PEEK_WAIT: 1790 LogFlowFunc(("[Client %RU32] GUEST_MSG_PEEK_WAIT\n", u32ClientID)); 1791 rc = clientMsgPeek(u32ClientID, callHandle, cParms, paParms, true /*fWait*/); 1792 break; 1793 case GUEST_MSG_GET: 1794 LogFlowFunc(("[Client %RU32] GUEST_MSG_GET\n", u32ClientID)); 1795 rc = clientMsgGet(u32ClientID, callHandle, cParms, paParms); 1796 break; 1797 case GUEST_MSG_CANCEL: 1798 LogFlowFunc(("[Client %RU32] GUEST_MSG_CANCEL\n", u32ClientID)); 1799 rc = clientMsgCancel(u32ClientID, cParms); 1800 break; 1801 1802 /* 1803 * The guest wants to close specific guest session. This is handy for 1804 * shutting down dedicated guest session processes from another process. 1805 */ 1806 case GUEST_SESSION_CLOSE: 1807 LogFlowFunc(("[Client %RU32] GUEST_SESSION_CLOSE\n", u32ClientID)); 1808 rc = sessionClose(u32ClientID, callHandle, cParms, paParms); 1809 break; 1810 1811 /* 1812 * For all other regular commands we call our hostCallback 1813 * function. If the current command does not support notifications, 1814 * notifyHost will return VERR_NOT_SUPPORTED. 1815 */ 1816 default: 1817 rc = hostCallback(eFunction, cParms, paParms); 1818 break; 1819 } 1820 1821 if (rc != VINF_HGCM_ASYNC_EXECUTE) 1822 { 1823 /* Tell the client that the call is complete (unblocks waiting). */ 1824 AssertPtr(mpHelpers); 1825 mpHelpers->pfnCallComplete(callHandle, rc); 1826 } 1827 } 1828 } 1829 catch (std::bad_alloc &) 1830 { 1831 rc = VERR_NO_MEMORY; 2086 default: 2087 rc = hostCallback(idFunction, cParms, paParms); 2088 break; 2089 2090 /* 2091 * The remaining commands are here for compatibility with older 2092 * guest additions: 2093 */ 2094 case GUEST_MSG_WAIT: 2095 LogFlowFunc(("[Client %RU32] GUEST_MSG_WAIT\n", idClient)); 2096 clientMsgOldGet(idClient, hCall, cParms, paParms); 2097 rc = VINF_HGCM_ASYNC_EXECUTE; 2098 break; 2099 2100 case GUEST_MSG_SKIP_OLD: 2101 LogFlowFunc(("[Client %RU32] GUEST_MSG_SKIP_OLD\n", idClient)); 2102 rc = clientMsgOldSkip(idClient, cParms); 2103 break; 2104 2105 case GUEST_MSG_FILTER_SET: 2106 LogFlowFunc(("[Client %RU32] GUEST_MSG_FILTER_SET\n", idClient)); 2107 rc = clientMsgOldFilterSet(idClient, cParms, paParms); 2108 break; 2109 2110 case GUEST_MSG_FILTER_UNSET: 2111 LogFlowFunc(("[Client %RU32] GUEST_MSG_FILTER_UNSET\n", idClient)); 2112 rc = VERR_NOT_IMPLEMENTED; 2113 break; 2114 } 2115 2116 if (rc != VINF_HGCM_ASYNC_EXECUTE) 2117 { 2118 /* Tell the client that the call is complete (unblocks waiting). */ 2119 LogFlowFunc(("[Client %RU32] Calling pfnCallComplete w/ rc=%Rrc\n", idClient, rc)); 2120 AssertPtr(mpHelpers); 2121 mpHelpers->pfnCallComplete(hCall, rc); 1832 2122 } 1833 2123 } 2124 1834 2125 1835 2126 /** … … 1838 2129 * @thread hgcm 1839 2130 */ 1840 int Service::hostCall(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 1841 { 1842 int rc = VERR_NOT_SUPPORTED; 1843 LogFlowFunc(("fn=%RU32, cParms=%RU32, paParms=0x%p\n", 1844 eFunction, cParms, paParms)); 1845 try 1846 { 1847 switch (eFunction) 1848 { 1849 /** 1850 * Host 1851 */ 1852 case HOST_CANCEL_PENDING_WAITS: 2131 int GstCtrlService::hostCall(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 2132 { 2133 LogFlowFunc(("fn=%RU32, cParms=%RU32, paParms=0x%p\n", eFunction, cParms, paParms)); 2134 2135 switch (eFunction) 2136 { 2137 default: 2138 return hostProcessCommand(eFunction, cParms, paParms); 2139 2140 /** @todo r=bird: Why is this here, I cannot find anyone using this in Main. 2141 * I thought the HOST_CANCEL_PENDING_WAITS was only for return to the _guest_ 2142 * when the root VBoxService wanted to shut down. */ 2143 case HOST_CANCEL_PENDING_WAITS: 2144 { 2145 LogFlowFunc(("HOST_CANCEL_PENDING_WAITS\n")); 2146 AssertFailed(); /* want to know who uses this function! */ 2147 ClientStateMapIter itClientState = mClientStateMap.begin(); 2148 while (itClientState != mClientStateMap.end()) 1853 2149 { 1854 LogFlowFunc(("HOST_CANCEL_PENDING_WAITS\n")); 1855 ClientStateMapIter itClientState = mClientStateMap.begin(); 1856 while (itClientState != mClientStateMap.end()) 1857 { 1858 int rc2 = itClientState->second.CancelWaiting(); 1859 if (RT_FAILURE(rc2)) 1860 LogFlowFunc(("Cancelling waiting for client ID=%RU32 failed with rc=%Rrc", 1861 itClientState->first, rc2)); 1862 ++itClientState; 1863 } 1864 rc = VINF_SUCCESS; 1865 break; 2150 int rc2 = itClientState->second.CancelWaiting(); 2151 if (RT_FAILURE(rc2)) 2152 LogFlowFunc(("Cancelling waiting for client ID=%RU32 failed with rc=%Rrc", 2153 itClientState->first, rc2)); 2154 ++itClientState; 1866 2155 } 1867 1868 default: 1869 rc = hostProcessCommand(eFunction, cParms, paParms); 1870 break; 1871 } 1872 } 1873 catch (std::bad_alloc &) 1874 { 1875 rc = VERR_NO_MEMORY; 1876 } 1877 1878 return rc; 2156 return VINF_SUCCESS; 2157 } 2158 } 1879 2159 } 1880 2160 1881 /** 1882 * Client asks another client (guest) session to close. 1883 * 1884 * @return IPRT status code. 1885 * @param u32ClientID The client's ID. 1886 * @param callHandle The client's call handle. 1887 * @param cParms Number of parameters. 1888 * @param paParms Array of parameters. 1889 */ 1890 int Service::sessionClose(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 1891 { 1892 RT_NOREF(u32ClientID, callHandle); 1893 if (cParms < 2) 1894 return VERR_INVALID_PARAMETER; 1895 1896 uint32_t uContextID, uFlags; 1897 int rc = HGCMSvcGetU32(&paParms[0], &uContextID); 1898 if (RT_SUCCESS(rc)) 1899 rc = HGCMSvcGetU32(&paParms[1], &uFlags); 1900 1901 uint32_t uSessionID = VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(uContextID); 1902 1903 if (RT_SUCCESS(rc)) 1904 rc = hostProcessCommand(HOST_SESSION_CLOSE, cParms, paParms); 1905 1906 LogFlowFunc(("Closing guest session ID=%RU32 (from client ID=%RU32) returned with rc=%Rrc\n", 1907 uSessionID, u32ClientID, rc)); NOREF(uSessionID); 1908 return rc; 1909 } 1910 1911 int Service::uninit(void) 2161 2162 int GstCtrlService::uninit(void) 1912 2163 { 1913 2164 return VINF_SUCCESS; 1914 2165 } 1915 2166 1916 } /* namespace guestControl */ 1917 1918 using guestControl::Service; 2167 1919 2168 1920 2169 /** … … 1942 2191 else 1943 2192 { 1944 Service *pService = NULL;2193 GstCtrlService *pService = NULL; 1945 2194 /* No exceptions may propagate outside. */ 1946 2195 try 1947 2196 { 1948 pService = new Service(pTable->pHelpers);2197 pService = new GstCtrlService(pTable->pHelpers); 1949 2198 } 1950 2199 catch (int rcThrown) … … 1966 2215 1967 2216 /* Register functions. */ 1968 pTable->pfnUnload = Service::svcUnload;1969 pTable->pfnConnect = Service::svcConnect;1970 pTable->pfnDisconnect = Service::svcDisconnect;1971 pTable->pfnCall = Service::svcCall;1972 pTable->pfnHostCall = Service::svcHostCall;1973 pTable->pfnSaveState = NULL; /* The service is stateless, so the normal */2217 pTable->pfnUnload = GstCtrlService::svcUnload; 2218 pTable->pfnConnect = GstCtrlService::svcConnect; 2219 pTable->pfnDisconnect = GstCtrlService::svcDisconnect; 2220 pTable->pfnCall = GstCtrlService::svcCall; 2221 pTable->pfnHostCall = GstCtrlService::svcHostCall; 2222 pTable->pfnSaveState = NULL; /* The GstCtrlService is stateless, so the normal */ 1974 2223 pTable->pfnLoadState = NULL; /* construction done before restoring suffices */ 1975 pTable->pfnRegisterExtension = Service::svcRegisterExtension;2224 pTable->pfnRegisterExtension = GstCtrlService::svcRegisterExtension; 1976 2225 1977 2226 /* Service specific initialization. */ -
trunk/src/VBox/Main/include/GuestSessionImpl.h
r75605 r75798 315 315 inline bool i_processExists(uint32_t uProcessID, ComObjPtr<GuestProcess> *pProcess); 316 316 inline int i_processGetByPID(ULONG uPID, ComObjPtr<GuestProcess> *pProcess); 317 int i_sendCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms); 317 int i_sendCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms, 318 uint64_t fDst = VBOX_GUESTCTRL_DST_SESSION); 318 319 static HRESULT i_setErrorExternal(VirtualBoxBase *pInterface, int guestRc); 319 320 int i_setSessionStatus(GuestSessionStatus_T sessionStatus, int sessionRc); -
trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp
r75737 r75798 1179 1179 } 1180 1180 1181 int GuestObject::sendCommand(uint32_t uFunction, 1182 uint32_t cParms, PVBOXHGCMSVCPARM paParms) 1181 int GuestObject::sendCommand(uint32_t uFunction, uint32_t cParms, PVBOXHGCMSVCPARM paParms) 1183 1182 { 1184 1183 #ifndef VBOX_GUESTCTRL_TEST_CASE … … 1192 1191 if (pVMMDev) 1193 1192 { 1193 /* HACK ALERT! We extend the first parameter to 64-bit and use the 1194 two topmost bits for call destination information. */ 1195 Assert(paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT); 1196 paParms[0].type = VBOX_HGCM_SVC_PARM_64BIT; 1197 paParms[0].u.uint64 = (uint64_t)paParms[0].u.uint32 | VBOX_GUESTCTRL_DST_SESSION; 1198 1199 /* Make the call. */ 1194 1200 LogFlowThisFunc(("uFunction=%RU32, cParms=%RU32\n", uFunction, cParms)); 1195 1201 vrc = pVMMDev->hgcmHostCall(HGCMSERVICE_NAME, uFunction, cParms, paParms); -
trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp
r75737 r75798 718 718 alock.release(); /* Drop the write lock before waiting. */ 719 719 720 vrc = i_sendCommand(HOST_SESSION_CLOSE, i, paParms );720 vrc = i_sendCommand(HOST_SESSION_CLOSE, i, paParms, VBOX_GUESTCTRL_DST_BOTH); 721 721 if (RT_SUCCESS(vrc)) 722 722 vrc = i_waitForStatusChange(pEvent, GuestSessionWaitForFlag_Terminate, uTimeoutMS, … … 1946 1946 alock.release(); /* Drop write lock before sending. */ 1947 1947 1948 vrc = i_sendCommand(HOST_SESSION_CREATE, i, paParms );1948 vrc = i_sendCommand(HOST_SESSION_CREATE, i, paParms, VBOX_GUESTCTRL_DST_ROOT_SVC); 1949 1949 if (RT_SUCCESS(vrc)) 1950 1950 { … … 2454 2454 } 2455 2455 2456 int GuestSession::i_sendCommand(uint32_t uFunction, 2457 uint 32_t uParms, PVBOXHGCMSVCPARM paParms)2456 int GuestSession::i_sendCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms, 2457 uint64_t fDst /*= VBOX_GUESTCTRL_DST_SESSION*/) 2458 2458 { 2459 2459 LogFlowThisFuncEnter(); … … 2467 2467 AssertPtr(pVMMDev); 2468 2468 2469 LogFlowThisFunc(("uFunction=%RU32, uParms=%RU32\n", uFunction, uParms)); 2469 LogFlowThisFunc(("uFunction=%RU32 (%s), uParms=%RU32\n", uFunction, GstCtrlHostFnName((guestControl::eHostFn)uFunction), uParms)); 2470 2471 /* HACK ALERT! We extend the first parameter to 64-bit and use the 2472 two topmost bits for call destination information. */ 2473 Assert(fDst == VBOX_GUESTCTRL_DST_SESSION || fDst == VBOX_GUESTCTRL_DST_ROOT_SVC || fDst == VBOX_GUESTCTRL_DST_BOTH); 2474 Assert(paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT); 2475 paParms[0].type = VBOX_HGCM_SVC_PARM_64BIT; 2476 paParms[0].u.uint64 = (uint64_t)paParms[0].u.uint32 | fDst; 2477 2478 /* Make the call. */ 2470 2479 int vrc = pVMMDev->hgcmHostCall(HGCMSERVICE_NAME, uFunction, uParms, paParms); 2471 2480 if (RT_FAILURE(vrc)) -
trunk/src/VBox/Main/src-client/HGCMThread.cpp
r75747 r75798 556 556 int HGCMThread::MsgComplete(HGCMMsgCore *pMsg, int32_t result) 557 557 { 558 LogFlow(("HGCMThread::MsgComplete: thread = %p, pMsg = %p \n", this, pMsg));558 LogFlow(("HGCMThread::MsgComplete: thread = %p, pMsg = %p, result = %Rrc (%d)\n", this, pMsg, result, result)); 559 559 560 560 AssertRelease(pMsg->m_pThread == this); … … 740 740 } 741 741 742 int hgcmMsgComplete(HGCMMsgCore *pMsg, int32_t u32Result)743 { 744 LogFlow(("MAIN::hgcmMsgComplete: pMsg = %p \n", pMsg));742 int hgcmMsgComplete(HGCMMsgCore *pMsg, int32_t rcMsg) 743 { 744 LogFlow(("MAIN::hgcmMsgComplete: pMsg = %p, rcMsg = %Rrc (%d)\n", pMsg, rcMsg, rcMsg)); 745 745 746 746 int rc; 747 747 if (pMsg) 748 rc = pMsg->Thread()->MsgComplete(pMsg, u32Result);748 rc = pMsg->Thread()->MsgComplete(pMsg, rcMsg); 749 749 else 750 750 rc = VINF_SUCCESS; 751 751 752 LogFlow(("MAIN::hgcmMsgComplete: pMsg = %p, rc = %Rrc\n", pMsg, rc));752 LogFlow(("MAIN::hgcmMsgComplete: pMsg = %p, rcMsg =%Rrc (%d), returns rc = %Rrc\n", pMsg, rcMsg, rcMsg, rc)); 753 753 return rc; 754 754 }
Note:
See TracChangeset
for help on using the changeset viewer.

