VirtualBox

Changeset 75798 in vbox


Ignore:
Timestamp:
Nov 28, 2018 11:47:11 PM (6 years ago)
Author:
vboxsync
Message:

VBoxGuestControl: Optimizing message handling - part 1. bugref:9313

Location:
trunk
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/HostServices/GuestControlSvc.h

    r75757 r75798  
    109109} VBOXGUESTCTRLHOSTCALLBACK, *PVBOXGUESTCTRLHOSTCALLBACK;
    110110
     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
    111124/**
    112125 * The service functions which are callable by host.
     
    204217};
    205218
     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 */
     225DECLINLINE(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
    206254/**
    207255 * The service functions which are called by guest. The numbers may not change,
     
    210258enum eGuestFn
    211259{
    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.
    214261     * This is a blocking call and can be deferred.
    215262     *
     
    231278     */
    232279    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
    241294     * 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.
    242298     */
    243299    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
    246301     * context ID scheme (that is, a specific session, object etc).
    247302     * Since VBox 4.3+.
     303     * @deprecated  Replaced by GUEST_SESSION_ACCEPT.
    248304     */
    249305    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,
    252309     */
    253310    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 stale
    257      * host commands in the queue.
    258      */
    259     GUEST_MSG_SKIP = 10,
    260     /**
    261      * General reply to a host message. Only contains basic data
    262      * along with a simple payload.
    263      */
    264     GUEST_MSG_REPLY = 11,
    265     /**
    266      * General message for updating a pending progress for
    267      * a long task.
    268      */
    269     GUEST_MSG_PROGRESS_UPDATE = 12,
    270 
    271311    /** Peeks at the next message, returning immediately.
    272312     *
     
    279319     * @retval  VINF_SUCCESS if a message was pending and is being returned.
    280320     * @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
    283324     * @since   6.0
    284325     */
    285     GUEST_MSG_PEEK_NOWAIT,
     326    GUEST_MSG_PEEK_NOWAIT = 6,
    286327    /** Peeks at the next message, waiting for one to arrive.
    287328     *
     
    294335     * @retval  VINF_SUCCESS if info about an pending message is being returned.
    295336     * @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.
    297338     * @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
    300342     * @note    This replaces GUEST_MSG_WAIT.
    301343     * @since   6.0
    302344     */
    303     GUEST_MSG_PEEK_WAIT,
     345    GUEST_MSG_PEEK_WAIT = 7,
    304346    /** Gets the next message, returning immediately.
    305347     *
     
    313355     * @retval  VERR_TRY_AGAIN if no message pending.
    314356     * @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.
    317357     * @retval  VERR_BUFFER_OVERFLOW if a parmeter buffer is too small.  The buffer
    318358     *          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
    320362     * @note    This replaces GUEST_MSG_WAIT.
    321363     * @since   6.0
    322364     */
    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
    334375     * @since   6.0
    335376     */
    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,
    338465    /**
    339466     * Guest reports back a guest session status.
     467     * @todo proper docs.
    340468     */
    341469    GUEST_SESSION_NOTIFY = 20,
    342470    /**
    343471     * Guest wants to close a specific guest session.
     472     * @todo proper docs.
    344473     */
    345474    GUEST_SESSION_CLOSE = 21,
     
    347476    /**
    348477     * Guests sends output from an executed process.
     478     * @todo proper docs.
    349479     */
    350480    GUEST_EXEC_OUTPUT = 100,
    351481    /**
    352482     * Guest sends a status update of an executed process to the host.
     483     * @todo proper docs.
    353484     */
    354485    GUEST_EXEC_STATUS = 101,
    355486    /**
    356487     * Guests sends an input status notification to the host.
     488     * @todo proper docs.
    357489     */
    358490    GUEST_EXEC_INPUT_STATUS = 102,
     
    362494     * how many data is available / can be sent without actually
    363495     * transmitting the data.
     496     * @todo proper docs.
    364497     */
    365498    GUEST_EXEC_IO_NOTIFY = 210,
    366499    /**
    367500     * Guest notifies the host about some directory event.
     501     * @todo proper docs.
    368502     */
    369503    GUEST_DIR_NOTIFY = 230,
    370504    /**
    371505     * Guest notifies the host about some file event.
     506     * @todo proper docs.
    372507     */
    373508    GUEST_FILE_NOTIFY = 240
    374509};
     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 */
     516DECLINLINE(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
    375548
    376549/**
  • trunk/include/VBox/VBoxGuestLib.h

    r75758 r75798  
    768768VBGLR3DECL(int) VbglR3GuestCtrlDisconnect(uint32_t idClient);
    769769VBGLR3DECL(int) VbglR3GuestCtrlMsgFilterSet(uint32_t uClientId, uint32_t uValue, uint32_t uMaskAdd, uint32_t uMaskRemove);
    770 VBGLR3DECL(int) VbglR3GuestCtrlMsgFilterUnset(uint32_t uClientId);
    771770VBGLR3DECL(int) VbglR3GuestCtrlMsgReply(PVBGLR3GUESTCTRLCMDCTX pCtx, int rc);
    772771VBGLR3DECL(int) VbglR3GuestCtrlMsgReplyEx(PVBGLR3GUESTCTRLCMDCTX pCtx, int rc, uint32_t uType,
    773772                                          void *pvPayload, uint32_t cbPayload);
    774 VBGLR3DECL(int) VbglR3GuestCtrlMsgSkip(uint32_t uClientId);
     773VBGLR3DECL(int) VbglR3GuestCtrlMsgSkipOld(uint32_t uClientId);
    775774VBGLR3DECL(int) VbglR3GuestCtrlMsgPeekWait(uint32_t idClient, uint32_t *pidMsg, uint32_t *pcParameters);
    776775VBGLR3DECL(int) VbglR3GuestCtrlCancelPendingWaits(HGCMCLIENTID idClient);
  • trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibGuestCtrl.cpp

    r75758 r75798  
    366366
    367367
    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 
    385368VBGLR3DECL(int) VbglR3GuestCtrlMsgReply(PVBGLR3GUESTCTRLCMDCTX pCtx,
    386369                                        int rc)
     
    416399 * @param   uClientId       The client ID returned by VbglR3GuestCtrlConnect().
    417400 */
    418 VBGLR3DECL(int) VbglR3GuestCtrlMsgSkip(uint32_t uClientId)
     401VBGLR3DECL(int) VbglR3GuestCtrlMsgSkipOld(uint32_t uClientId)
    419402{
    420403    HGCMMsgCmdSkip Msg;
    421404
    422405    /* 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);
    424407    VbglHGCMParmUInt32Set(&Msg.flags, 0 /* Flags, unused */);
    425408    return VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
     
    436419{
    437420    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);
    439422    return VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
    440423}
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp

    r75758 r75798  
    361361                         * skip all not wanted messages here.
    362362                         */
    363                         rc = VbglR3GuestCtrlMsgSkip(g_uControlSvcClientID);
     363                        rc = VbglR3GuestCtrlMsgSkipOld(g_uControlSvcClientID);
    364364                        VGSvcVerbose(3, "Skipping uMsg=%RU32, cParms=%RU32, rc=%Rrc\n", uMsg, cParms, rc);
    365365                    }
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlSession.cpp

    r75758 r75798  
    10671067        VGSvcVerbose(3, "Unsupported message (uMsg=%RU32, cParms=%RU32) from host, skipping\n", uMsg, pHostCtx->uNumParms);
    10681068
    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 
    10721069        /*
    10731070         * !!! HACK ALERT BEGIN !!!
     
    11031100
    11041101        /* Tell the host service to skip the message. */
    1105         VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID);
     1102        VbglR3GuestCtrlMsgSkipOld(pHostCtx->uClientID);
    11061103
    11071104        rc = VINF_SUCCESS;
  • trunk/src/VBox/HostServices/GuestControl/service.cpp

    r75773 r75798  
    6060*   Header Files                                                                                                                 *
    6161*********************************************************************************************************************************/
    62 #ifdef LOG_GROUP
    63  #undef LOG_GROUP
    64 #endif
    6562#define LOG_GROUP LOG_GROUP_GUEST_CONTROL
    6663#include <VBox/HostServices/GuestControlSvc.h>
     
    6865#include <VBox/log.h>
    6966#include <VBox/AssertGuest.h>
     67#include <VBox/VMMDev.h>
    7068#include <iprt/assert.h>
    7169#include <iprt/cpp/autores.h>
     
    8078
    8179#include <map>
    82 #include <memory>  /* for auto_ptr */
     80#include <new>      /* for std::nothrow*/
    8381#include <string>
    8482#include <list>
    8583
    8684
    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)
     85using namespace guestControl;
     86
    9287
    9388/**
     
    114109typedef struct HostCommand
    115110{
    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);
    137138    }
    138139
    139140    /**
    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.
    142183     *
    143      * Needs to be freed using Free().
     184     * The specified parameters are copied and any buffers referenced by it
     185     * duplicated as well.
    144186     *
    145187     * @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);
    157205        AssertPtrReturn(paParms, VERR_INVALID_POINTER);
    158206
    159         /* Paranoia. */
    160         if (cParms > 256)
    161             cParms = 256;
    162 
    163         int rc = VINF_SUCCESS;
    164 
    165207        /*
    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.
    169209         */
    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;
    171227        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)
    182235            {
    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;
    217238                    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);
    218258            }
    219259        }
    220260
    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
    273270
    274271    /**
     
    282279    int CopyTo(VBOXHGCMSVCPARM paDstParms[], uint32_t cDstParms) const
    283280    {
    284         LogFlowThisFunc(("[Cmd %RU32] mParmCount=%RU32, mContextID=%RU32 (Session %RU32)\n",
    285                          mMsgType, mParmCount, mContextID, 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)));
    286283
    287284        int rc = VINF_SUCCESS;
     
    423420        return VERR_TOO_MUCH_DATA;
    424421    }
    425 
    426     /** Reference count for keeping track how many connected
    427      *  clients still need to process this command until it can
    428      *  be removed. */
    429     uint32_t mRefCount;
    430     /** The context ID this command belongs to. Will be extracted
    431      *  *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;
    441422} HostCommand;
    442423typedef std::list< HostCommand *> HostCmdList;
     
    467448{
    468449    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)
    477458    { }
    478459
    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)
    488469    { }
    489470
    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();
    507478        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. */
    520483        mHostCmdRc    = VINF_SUCCESS;
    521484        mHostCmdTries = 0;
    522485        mPeekCount    = 0;
    523 
    524         return nextItem;
    525486    }
    526487
     
    529490        AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER);
    530491
    531         int rc = VINF_SUCCESS;
    532 
    533492        try
    534493        {
    535494            mHostCmdList.push_back(pHostCmd);
    536             pHostCmd->AddRef();
    537495        }
    538496        catch (std::bad_alloc &)
    539497        {
    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;
    590503    }
    591504
     
    640553     * @note Only used by GUEST_MSG_WAIT scenarios.
    641554     */
    642     int OldRun(ClientConnection const *pConnection,
    643                HostCommand            *pHostCmd)
     555    int OldRun(ClientConnection const *pConnection, HostCommand *pHostCmd)
    644556    {
    645557        AssertPtrReturn(pConnection, VERR_INVALID_POINTER);
    646558        AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER);
     559        Assert(*mHostCmdList.begin() == pHostCmd);
    647560
    648561        LogFlowFunc(("[Client %RU32] pConnection=%p, mHostCmdRc=%Rrc, mHostCmdTries=%RU32, mPeekCount=%RU32\n",
     
    691604        if (fRemove)
    692605        {
    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();
    705608        }
    706609
     
    758661                AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER);
    759662
    760                 LogFlowThisFunc(("[Client %RU32] Current host command is %RU32 (CID=%RU32, cParms=%RU32, refCount=%RU32)\n",
    761                                  mID, pHostCmd->mMsgType, pHostCmd->mContextID, 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));
    762665
    763666                if (mIsPending == GUEST_MSG_PEEK_WAIT)
     
    791694
    792695    /**
    793      * Used by Service::call() to handle GUEST_CANCEL_PENDING_WAITS.
     696     * Used by Service::call() to handle GUEST_MSG_CANCEL.
    794697     *
    795698     * @note This cancels both GUEST_MSG_WAIT and GUEST_MSG_PEEK_WAIT sleepers.
     
    797700    int CancelWaiting()
    798701    {
    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. */
    801707
    802708        int rc;
     
    892798    /** The client's ID. */
    893799    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;
    900800    /** Host command list to process. */
    901801    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     * @{ */
    902817    /** Last (most recent) rc after handling the host command. */
    903818    int mHostCmdRc;
     
    907822     * to be able to successfully retrieve.  */
    908823    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 return
    915      * from the waiting call until a new host command is available.
    916      */
    917     guestControl::eGuestFn mIsPending;
    918824    /** Number of times we've peeked at a pending message.
    919825     *
     
    924830     */
    925831    uint32_t mPeekCount;
    926     /** The client's pending connection. */
    927     ClientConnection mPendingCon;
     832    /** @} */
     833
    928834} ClientState;
    929835typedef std::map< uint32_t, ClientState > ClientStateMap;
     
    932838
    933839/**
     840 * Prepared session (GUEST_SESSION_PREPARE).
     841 */
     842typedef 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/**
    934856 * Class containing the shared information service functionality.
    935857 */
    936 class Service : public RTCNonCopyable
     858class GstCtrlService : public RTCNonCopyable
    937859{
    938860
     
    940862
    941863    /** Type definition for use in callback functions. */
    942     typedef Service SELF;
     864    typedef GstCtrlService SELF;
    943865    /** HGCM helper functions. */
    944866    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. */
    949868    PFNHGCMSVCEXT mpfnHostCallback;
    950869    /** User data pointer to be supplied to the host callback function. */
     
    952871    /** List containing all buffered host commands. */
    953872    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
    957884public:
    958     explicit Service(PVBOXHGCMSVCHELPERS pHelpers)
     885    explicit GstCtrlService(PVBOXHGCMSVCHELPERS pHelpers)
    959886        : mpHelpers(pHelpers)
    960887        , mpfnHostCallback(NULL)
    961888        , mpvHostData(NULL)
     889        , m_idMasterClient(UINT32_MAX)
     890        , m_fLegacyMode(true)
     891        , m_cPreparedSessions(0)
    962892    {
    963893        RTListInit(&mHostCmdList);
     894        RTListInit(&m_PreparedSessions);
    964895    }
    965896
    966897    /**
    967898     * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnUnload}
    968      * Simply deletes the service object
     899     * Simply deletes the GstCtrlService object
    969900     */
    970901    static DECLCALLBACK(int) svcUnload(void *pvService)
     
    988919                                        uint32_t fRequestor, bool fRestoring)
    989920    {
    990         RT_NOREF(fRequestor, fRestoring);
     921        RT_NOREF(fRestoring);
    991922        AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
    992923        SELF *pSelf = reinterpret_cast<SELF *>(pvService);
    993924        AssertPtrReturn(pSelf, VERR_INVALID_POINTER);
    994         return pSelf->clientConnect(u32ClientID, pvClient);
     925        return pSelf->clientConnect(u32ClientID, pvClient, fRequestor);
    995926    }
    996927
     
    1063994
    1064995    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);
    1066997    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
    10671009    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
    10741013    int hostCallback(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
    10751014    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[]);
    10771017    int hostCall(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
    1078     int sessionClose(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
    10791018    int uninit(void);
    10801019
    1081     DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(Service);
     1020    DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(GstCtrlService);
    10821021};
    10831022
     1023
    10841024/**
    10851025 * Handles a client which just connected.
    10861026 *
    10871027 * @return  IPRT status code.
    1088  * @param   u32ClientID
     1028 * @param   idClient
    10891029 * @param   pvClient
    1090  */
    1091 int Service::clientConnect(uint32_t u32ClientID, void *pvClient)
     1030 * @param   fRequestor  VMMDevRequestHeader::fRequestor value, if available.
     1031 */
     1032int GstCtrlService::clientConnect(uint32_t idClient, void *pvClient, uint32_t fRequestor)
    10921033{
    10931034    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
    11071070    return VINF_SUCCESS;
    11081071}
    11091072
     1073
    11101074/**
    11111075 * Handles a client which disconnected.
     
    11151079 *
    11161080 * @return  IPRT status code.
    1117  * @param   u32ClientID             The 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 */
     1084int GstCtrlService::clientDisconnect(uint32_t idClient, void *pvClient)
    11211085{
    11221086    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)
    11661108            {
    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);
    11701115            }
    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;
    11871147}
     1148
    11881149
    11891150/**
     
    11991160 * @param   paParms                     Array of parameters.
    12001161 */
    1201 int Service::clientMsgOldGet(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle,
    1202                              uint32_t cParms, VBOXHGCMSVCPARM paParms[])
     1162int GstCtrlService::clientMsgOldGet(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle,
     1163                                    uint32_t cParms, VBOXHGCMSVCPARM paParms[])
    12031164{
    12041165    /*
     
    12291190}
    12301191
    1231 /**
    1232  * Implements GUEST_MSG_PEEK_WAIT and GUEST_MSG_PEEK_NOWAIT.
     1192
     1193/**
     1194 * Implements GUEST_MAKE_ME_MASTER.
    12331195 *
    12341196 * @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  VINF_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
    12411203 *
    12421204 * @param   idClient    The client's ID.
     
    12471209 *                      immediately.
    12481210 */
    1249 int Service::clientMsgPeek(uint32_t idClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool fWait)
     1211int GstCtrlService::clientMakeMeMaster(uint32_t idClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms)
    12501212{
    12511213    /*
    12521214     * Validate the request.
    12531215     */
    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 */
     1264int 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);
    12551270    for (uint32_t i = 0; i < cParms; i++)
    12561271    {
    12571272        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);
    12591274        paParms[i].u.uint32 = 0;
    12601275    }
    12611276
    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;
    12661280
    12671281    /*
     
    12821296            }
    12831297
    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));
    12861300        return VINF_SUCCESS;
    12871301    }
     
    13151329 * @retval  VERR_TRY_AGAIN if no message pending.
    13161330 * @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.)
    13181334 * @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.
    13231336 *
    13241337 * @param   idClient    The client's ID.
     
    13271340 * @param   paParms     Array of parameters.
    13281341 */
    1329 int Service::clientMsgGet(uint32_t idClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
     1342int GstCtrlService::clientMsgGet(uint32_t idClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
    13301343{
    13311344    /*
     
    13391352                                 : UINT32_MAX;
    13401353
    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;
    13451358
    13461359    /*
     
    13531366
    13541367        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),
    13571371                                VERR_MISMATCH);
    13581372        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);
    13621377
    13631378        /* Check the parameter types. */
    13641379        for (uint32_t i = 0; i < cParms; i++)
    13651380            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);
    13681384
    13691385        /*
     
    14141430            {
    14151431                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();
    14211433            }
     1434            else
     1435                LogFunc(("pfnCallComplete -> %Rrc\n", rc));
    14221436            return VINF_HGCM_ASYNC_EXECUTE; /* The caller must not complete it. */
    14231437        }
     
    14371451 * @retval  VINF_SUCCESS if cancelled any calls.
    14381452 * @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.
    14411453 * @retval  VINF_HGCM_ASYNC_EXECUTE if message wait is pending.
    14421454 *
     
    14441456 * @param   cParms      Number of parameters.
    14451457 */
    1446 int Service::clientMsgCancel(uint32_t idClient, uint32_t cParms)
     1458int GstCtrlService::clientMsgCancel(uint32_t idClient, uint32_t cParms)
    14471459{
    14481460    /*
    14491461     * Validate the request.
    14501462     */
    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
    14571469    if (rClientState.mIsPending != 0)
    14581470    {
     
    14651477
    14661478/**
    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 */
     1489int 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 */
     1554int 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);
    14961603    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 */
     1628int 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)
    15061664            {
    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;
    15201669            }
    15211670        }
    15221671    }
    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 */
     1692int 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 */
     1761int 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));
    15241788    return rc;
    15251789}
    15261790
    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.
    15291794 *
    15301795 * @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 */
     1800int 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    }
    15611853    return VINF_SUCCESS;
    15621854}
    15631855
    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.
    15671863 *
    15681864 * @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 */
     1868int 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;
    15971887}
     1888
    15981889
    15991890/**
     
    16061897 * @param   paParms                 Array of parameters.
    16071898 */
    1608 int Service::hostCallback(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
     1899int GstCtrlService::hostCallback(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
    16091900{
    16101901    LogFlowFunc(("eFunction=%ld, cParms=%ld, paParms=%p\n",
     
    16151906    {
    16161907        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        }
    16181923    }
    16191924    else
     
    16241929}
    16251930
     1931
    16261932/**
    16271933 * Processes a command received from the host side and re-routes it to
     
    16291935 *
    16301936 * @return  IPRT status code.
    1631  * @param   eFunction               Function 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 */
     1941int GstCtrlService::hostProcessCommand(uint32_t idFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
    16361942{
    16371943    /*
     
    16421948     */
    16431949    if (mClientStateMap.empty())
     1950    {
     1951        LogFlow(("GstCtrlService::hostProcessCommand: VERR_NOT_FOUND!\n"));
    16441952        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);
    16611959    if (RT_SUCCESS(rc))
    16621960    {
    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()));
    16651964
    16661965        /*
    1667          * Wake up all pending clients which are interested in this
    1668          * 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.
    16691968         */
    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)
    16821977            {
    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                }
    16931989            }
    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));
    17072019    return rc;
    17082020}
     2021
    17092022
    17102023/**
     
    17172030 * @thread  HGCM
    17182031 */
    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     {
     2032void 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
    17282081        /*
    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.
    17302085         */
    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);
    18322122    }
    18332123}
     2124
    18342125
    18352126/**
     
    18382129 * @thread  hgcm
    18392130 */
    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:
     2131int 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())
    18532149            {
    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;
    18662155            }
    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    }
    18792159}
    18802160
    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
     2162int GstCtrlService::uninit(void)
    19122163{
    19132164    return VINF_SUCCESS;
    19142165}
    19152166
    1916 } /* namespace guestControl */
    1917 
    1918 using guestControl::Service;
     2167
    19192168
    19202169/**
     
    19422191        else
    19432192        {
    1944             Service *pService = NULL;
     2193            GstCtrlService *pService = NULL;
    19452194            /* No exceptions may propagate outside. */
    19462195            try
    19472196            {
    1948                 pService = new Service(pTable->pHelpers);
     2197                pService = new GstCtrlService(pTable->pHelpers);
    19492198            }
    19502199            catch (int rcThrown)
     
    19662215
    19672216                /* 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 */
    19742223                pTable->pfnLoadState          = NULL;  /* construction done before restoring suffices */
    1975                 pTable->pfnRegisterExtension  = Service::svcRegisterExtension;
     2224                pTable->pfnRegisterExtension  = GstCtrlService::svcRegisterExtension;
    19762225
    19772226                /* Service specific initialization. */
  • trunk/src/VBox/Main/include/GuestSessionImpl.h

    r75605 r75798  
    315315    inline bool             i_processExists(uint32_t uProcessID, ComObjPtr<GuestProcess> *pProcess);
    316316    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);
    318319    static HRESULT          i_setErrorExternal(VirtualBoxBase *pInterface, int guestRc);
    319320    int                     i_setSessionStatus(GuestSessionStatus_T sessionStatus, int sessionRc);
  • trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp

    r75737 r75798  
    11791179}
    11801180
    1181 int GuestObject::sendCommand(uint32_t uFunction,
    1182                              uint32_t cParms, PVBOXHGCMSVCPARM paParms)
     1181int GuestObject::sendCommand(uint32_t uFunction, uint32_t cParms, PVBOXHGCMSVCPARM paParms)
    11831182{
    11841183#ifndef VBOX_GUESTCTRL_TEST_CASE
     
    11921191    if (pVMMDev)
    11931192    {
     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. */
    11941200        LogFlowThisFunc(("uFunction=%RU32, cParms=%RU32\n", uFunction, cParms));
    11951201        vrc = pVMMDev->hgcmHostCall(HGCMSERVICE_NAME, uFunction, cParms, paParms);
  • trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp

    r75737 r75798  
    718718    alock.release(); /* Drop the write lock before waiting. */
    719719
    720     vrc = i_sendCommand(HOST_SESSION_CLOSE, i, paParms);
     720    vrc = i_sendCommand(HOST_SESSION_CLOSE, i, paParms, VBOX_GUESTCTRL_DST_BOTH);
    721721    if (RT_SUCCESS(vrc))
    722722        vrc = i_waitForStatusChange(pEvent, GuestSessionWaitForFlag_Terminate, uTimeoutMS,
     
    19461946    alock.release(); /* Drop write lock before sending. */
    19471947
    1948     vrc = i_sendCommand(HOST_SESSION_CREATE, i, paParms);
     1948    vrc = i_sendCommand(HOST_SESSION_CREATE, i, paParms, VBOX_GUESTCTRL_DST_ROOT_SVC);
    19491949    if (RT_SUCCESS(vrc))
    19501950    {
     
    24542454}
    24552455
    2456 int GuestSession::i_sendCommand(uint32_t uFunction,
    2457                                 uint32_t uParms, PVBOXHGCMSVCPARM paParms)
     2456int GuestSession::i_sendCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms,
     2457                                uint64_t fDst /*= VBOX_GUESTCTRL_DST_SESSION*/)
    24582458{
    24592459    LogFlowThisFuncEnter();
     
    24672467    AssertPtr(pVMMDev);
    24682468
    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. */
    24702479    int vrc = pVMMDev->hgcmHostCall(HGCMSERVICE_NAME, uFunction, uParms, paParms);
    24712480    if (RT_FAILURE(vrc))
  • trunk/src/VBox/Main/src-client/HGCMThread.cpp

    r75747 r75798  
    556556int HGCMThread::MsgComplete(HGCMMsgCore *pMsg, int32_t result)
    557557{
    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));
    559559
    560560    AssertRelease(pMsg->m_pThread == this);
     
    740740}
    741741
    742 int hgcmMsgComplete(HGCMMsgCore *pMsg, int32_t u32Result)
    743 {
    744     LogFlow(("MAIN::hgcmMsgComplete: pMsg = %p\n", pMsg));
     742int hgcmMsgComplete(HGCMMsgCore *pMsg, int32_t rcMsg)
     743{
     744    LogFlow(("MAIN::hgcmMsgComplete: pMsg = %p, rcMsg = %Rrc (%d)\n", pMsg, rcMsg, rcMsg));
    745745
    746746    int rc;
    747747    if (pMsg)
    748         rc = pMsg->Thread()->MsgComplete(pMsg, u32Result);
     748        rc = pMsg->Thread()->MsgComplete(pMsg, rcMsg);
    749749    else
    750750        rc = VINF_SUCCESS;
    751751
    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));
    753753    return rc;
    754754}
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette