VirtualBox

Changeset 28557 in vbox


Ignore:
Timestamp:
Apr 21, 2010 11:18:32 AM (15 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
60367
Message:

Guest Control: Update (first stuff for piping output).

Location:
trunk
Files:
12 edited

Legend:

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

    r28434 r28557  
    9898    /** Size of optional data buffer (not used atm). */
    9999    uint32_t cbData;
    100 
    101100} HOSTEXECCALLBACKDATA, *PHOSTEXECCALLBACKDATA;
    102101
     102typedef struct _VBoxGuestCtrlExecOutCallbackData
     103{
     104    /** Callback data header. */
     105    HOSTCCALLBACKHEADER hdr;
     106    /** The process ID (PID). */
     107    uint32_t u32PID;
     108    /* The handle ID (stdout/stderr). */
     109    uint32_t u32HandleId;
     110    /** Optional flags (not used atm). */
     111    uint32_t u32Flags;
     112    /** Optional data buffer. */
     113    void *pvData;
     114    /** Size of optional data buffer. */
     115    uint32_t cbData;
     116} HOSTEXECOUTCALLBACKDATA, *PHOSTEXECOUTCALLBACKDATA;
     117
    103118enum
    104119{
    105     /** Magic number for sanity checking the HOSTEXECCALLBACKDATA structure */
    106     HOSTEXECCALLBACKDATAMAGIC = 0x26011982
     120    /** Magic number for sanity checking the HOSTEXECCALLBACKDATA structure. */
     121    HOSTEXECCALLBACKDATAMAGIC = 0x26011982,
     122    /** Magic number for sanity checking the HOSTEXECOUTCALLBACKDATA structure. */
     123    HOSTEXECOUTCALLBACKDATAMAGIC = 0x11061949
    107124};
    108125
     
    120137     * Sends input data for stdin to a running process executed by HOST_EXEC_CMD.
    121138     */
    122     HOST_EXEC_SEND_STDIN = 2,
     139    HOST_EXEC_SET_INPUT = 2,
    123140    /**
    124141     * Gets the current status of a running process, e.g.
    125142     * new data on stdout/stderr, process terminated etc.
    126143     */
    127     HOST_EXEC_GET_STATUS = 3
     144    HOST_EXEC_GET_OUTPUT = 3
    128145};
    129146
     
    141158     * TODO
    142159     */
    143     GUEST_EXEC_SEND_STDOUT = 3,
     160    GUEST_EXEC_SEND_OUTPUT = 2,
    144161    /**
    145162     * TODO
    146163     */
    147     GUEST_EXEC_SEND_STDERR = 4,
    148     /**
    149      * TODO
    150      */
    151     GUEST_EXEC_SEND_STATUS = 5
     164    GUEST_EXEC_SEND_STATUS = 3
    152165};
    153166
     
    162175     * or starting a program.
    163176     */
    164     GETHOSTMSG_EXEC_CMD = 1,
     177    GETHOSTMSG_EXEC_START_PROCESS = 1,
    165178    /**
    166179     * Sends input data for stdin to a running process executed by HOST_EXEC_CMD.
    167180     */
    168     GETHOSTMSG_EXEC_STDIN = 2
     181    GETHOSTMSG_EXEC_SEND_INPUT = 2,
     182    /**
     183     * Host requests the so far collected stdout/stderr output
     184     * from a running process executed by HOST_EXEC_CMD.
     185     */
     186    GETHOSTMSG_EXEC_GET_OUTPUT = 3
    169187};
    170188
     
    220238
    221239} VBoxGuestCtrlHGCMMsgExecCmd;
     240
     241typedef struct _VBoxGuestCtrlHGCMMsgExecOut
     242{
     243    VBoxGuestHGCMCallInfo hdr;
     244    /** Context ID. */
     245    HGCMFunctionParameter context;
     246    /** The process ID (PID). */
     247    HGCMFunctionParameter pid;
     248    /** The pipe handle ID. */
     249    HGCMFunctionParameter handle;
     250    /** Optional flags. */
     251    HGCMFunctionParameter flags;
     252    /** Data buffer. */
     253    HGCMFunctionParameter data;
     254
     255} VBoxGuestCtrlHGCMMsgExecOut;
    222256
    223257typedef struct _VBoxGuestCtrlHGCMMsgExecStatus
     
    241275typedef struct _VBoxGuestCtrlParamBuffer
    242276{
     277    uint32_t uMsg;
    243278    uint32_t uParmCount;
    244279    VBOXHGCMSVCPARM *pParms;
  • trunk/include/VBox/VBoxGuestLib.h

    r28441 r28557  
    526526                                                  char     *pszPassword,    uint32_t  cbPassword,
    527527                                                  uint32_t *puTimeLimit);
     528VBGLR3DECL(int) VbglR3GuestCtrlExecGetHostCmdOutput(uint32_t  u32ClientId,    uint32_t  uNumParms,
     529                                                    uint32_t *puContext,      uint32_t *puPID,
     530                                                    uint32_t *puHandle,       uint32_t *puFlags);
    528531VBGLR3DECL(int)     VbglR3GuestCtrlExecReportStatus(uint32_t  u32ClientId,
    529532                                                    uint32_t  u32Context,
     
    533536                                                    void     *pvData,
    534537                                                    uint32_t  cbData);
     538VBGLR3DECL(int)     VbglR3GuestCtrlExecSendOut(uint32_t     u32ClientId,
     539                                               uint32_t     u32Context,
     540                                               uint32_t     u32PID,
     541                                               uint32_t     u32Handle,
     542                                               uint32_t     u32Flags,
     543                                               void        *pvData,
     544                                               uint32_t     cbData);
    535545/** @}  */
    536546# endif /* VBOX_WITH_GUEST_CONTROL defined */
  • trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGuestCtrl.cpp

    r28434 r28557  
    146146 * @returns VBox status code.
    147147 * @param   u32ClientId     The client id returned by VbglR3GuestCtrlConnect().
    148  * @param   ppvData
    149148 * @param   uNumParms
    150149 ** @todo Docs!
     
    223222
    224223
     224/**
     225 * Allocates and gets host data, based on the message id.
     226 *
     227 * This will block until data becomes available.
     228 *
     229 * @returns VBox status code.
     230 * @param   u32ClientId     The client id returned by VbglR3GuestCtrlConnect().
     231 * @param   uNumParms
     232 ** @todo Docs!
     233 */
     234VBGLR3DECL(int) VbglR3GuestCtrlExecGetHostCmdOutput(uint32_t  u32ClientId,    uint32_t  uNumParms,
     235                                                    uint32_t *puContext,      uint32_t *puPID,
     236                                                    uint32_t *puHandle,       uint32_t *puFlags)
     237{
     238    AssertPtr(puContext);
     239    AssertPtr(puPID);
     240
     241    VBoxGuestCtrlHGCMMsgExecOut Msg;
     242
     243    Msg.hdr.result = VERR_WRONG_ORDER;
     244    Msg.hdr.u32ClientID = u32ClientId;
     245    Msg.hdr.u32Function = GUEST_GET_HOST_MSG;
     246    Msg.hdr.cParms = uNumParms;
     247
     248    VbglHGCMParmUInt32Set(&Msg.context, 0); /** @todo Put this some header struct! */
     249    VbglHGCMParmUInt32Set(&Msg.pid, 0);
     250    VbglHGCMParmUInt32Set(&Msg.handle, 0);   
     251    VbglHGCMParmUInt32Set(&Msg.flags, 0);
     252
     253    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     254    if (RT_SUCCESS(rc))
     255    {
     256        int rc2 = Msg.hdr.result;
     257        if (RT_FAILURE(rc2))
     258        {
     259            rc = rc2;
     260        }
     261        else
     262        {
     263            Msg.context.GetUInt32(puContext);
     264            Msg.pid.GetUInt32(puPID);
     265            Msg.handle.GetUInt32(puHandle);
     266            Msg.flags.GetUInt32(puFlags);           
     267        }
     268    }
     269    return rc;
     270}
    225271
    226272
     
    262308}
    263309
     310
     311/**
     312 * Sends output (from stdout/stderr) from a running process.
     313 *
     314 * @returns VBox status code.
     315 ** @todo Docs!
     316 */
     317VBGLR3DECL(int) VbglR3GuestCtrlExecSendOut(uint32_t     u32ClientId,
     318                                           uint32_t     u32Context,
     319                                           uint32_t     u32PID,
     320                                           uint32_t     u32Handle,
     321                                           uint32_t     u32Flags,
     322                                           void        *pvData,
     323                                           uint32_t     cbData)
     324{
     325    VBoxGuestCtrlHGCMMsgExecOut Msg;
     326
     327    Msg.hdr.result = VERR_WRONG_ORDER;
     328    Msg.hdr.u32ClientID = u32ClientId;
     329    Msg.hdr.u32Function = GUEST_EXEC_SEND_OUTPUT;
     330    Msg.hdr.cParms = 5;
     331
     332    VbglHGCMParmUInt32Set(&Msg.context, u32Context);
     333    VbglHGCMParmUInt32Set(&Msg.pid, u32PID);
     334    VbglHGCMParmUInt32Set(&Msg.handle, u32Handle);
     335    VbglHGCMParmUInt32Set(&Msg.flags, u32Flags);
     336    VbglHGCMParmPtrSet(&Msg.data, pvData, cbData);
     337
     338    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     339    if (RT_SUCCESS(rc))
     340    {
     341        int rc2 = Msg.hdr.result;
     342        if (RT_FAILURE(rc2))
     343            rc = rc2;
     344    }
     345    return rc;
     346}
     347
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp

    r28446 r28557  
    100100
    101101
    102 static int VBoxServiceControlHandleCmdExec(uint32_t u32ClientId, uint32_t uNumParms)
     102static int VBoxServiceControlHandleCmdStartProcess(uint32_t u32ClientId, uint32_t uNumParms)
    103103{
    104104    uint32_t uContextID;
     
    142142    if (RT_FAILURE(rc))
    143143    {
    144         VBoxServiceError("Control: Failed to retrieve execution command! Error: %Rrc\n", rc);
     144        VBoxServiceError("Control: Failed to retrieve exec start command! Error: %Rrc\n", rc);
    145145    }
    146146    else
     
    150150                                           szStdIn, szStdOut, szStdErr,
    151151                                           szUser, szPassword, uTimeLimitMS);
     152    }
     153    return rc;
     154}
     155
     156
     157static int VBoxServiceControlHandleCmdGetOutput(uint32_t u32ClientId, uint32_t uNumParms)
     158{
     159    uint32_t uContextID;
     160    uint32_t uPID;
     161    uint32_t uHandleID;
     162    uint32_t uFlags;
     163
     164    int rc = VbglR3GuestCtrlExecGetHostCmdOutput(u32ClientId, uNumParms,
     165                                                 &uContextID, &uPID, &uHandleID, &uFlags);
     166    if (RT_FAILURE(rc))
     167    {
     168        VBoxServiceError("Control: Failed to retrieve exec output command! Error: %Rrc\n", rc);
     169    }
     170    else
     171    {
     172        /* Let's have a look if we have a running process with PID = uPID ... */
     173        PVBOXSERVICECTRLTHREAD pNode;
     174        bool bFound = false;
     175        RTListForEach(&g_GuestControlExecThreads, pNode, VBOXSERVICECTRLTHREAD, Node)
     176        {
     177            if (   pNode->fStarted
     178                && pNode->enmType == VBoxServiceCtrlThreadDataExec)
     179            {
     180                PVBOXSERVICECTRLTHREADDATAEXEC pData = (PVBOXSERVICECTRLTHREADDATAEXEC)pNode->pvData;
     181                if (pData && pData->uPID == uPID)
     182                {
     183                    bFound = true;
     184                    break;
     185                }
     186            }
     187        }
     188
     189        if (bFound)
     190        {
     191            PVBOXSERVICECTRLTHREADDATAEXEC pData = (PVBOXSERVICECTRLTHREADDATAEXEC)pNode->pvData;
     192            AssertPtr(pData);
     193
     194            uint32_t cbRead = _4K; /* Try reading 4k. */
     195            BYTE *pBuf = (BYTE*)RTMemAlloc(cbRead);
     196            if (pBuf)
     197            {
     198                rc = VBoxServiceControlExecReadPipeBufferContent(&pData->stdOut, pBuf, cbRead, &cbRead);
     199                if (RT_SUCCESS(rc))
     200                {   
     201                    AssertPtr(pBuf);
     202                    /* cbRead now contains actual size. */
     203                    rc = VbglR3GuestCtrlExecSendOut(u32ClientId, uContextID, uPID, 0 /* handle ID */, 0 /* flags */,
     204                                                    pBuf, cbRead);
     205                }
     206                RTMemFree(pBuf);
     207            }
     208            else
     209                rc = VERR_NO_MEMORY;
     210        }
     211        else
     212            rc = VERR_NOT_FOUND; /* PID not found! */
    152213    }
    153214    return rc;
     
    176237        uint32_t uMsg;
    177238        uint32_t uNumParms;
    178         VBoxServiceVerbose(3, "Control: Waiting for host msg ...\n");
     239        VBoxServiceVerbose(4, "Control: Waiting for host msg ...\n");
    179240        rc = VbglR3GuestCtrlGetHostMsg(g_GuestControlSvcClientID, &uMsg, &uNumParms, 1000 /* 1s timeout */);
    180241        if (rc == VERR_TOO_MUCH_DATA)
     
    190251        if (RT_SUCCESS(rc))
    191252        {
     253            VBoxServiceVerbose(3, "Control: Msg=%u (%u parms) retrieved\n", uMsg, uNumParms);
    192254            switch(uMsg)
    193255            {
    194                 case GETHOSTMSG_EXEC_CMD:
    195                     rc = VBoxServiceControlHandleCmdExec(g_GuestControlSvcClientID, uNumParms);
     256                case GETHOSTMSG_EXEC_START_PROCESS:
     257                    rc = VBoxServiceControlHandleCmdStartProcess(g_GuestControlSvcClientID, uNumParms);
    196258                    break;
    197259
     260                case GETHOSTMSG_EXEC_GET_OUTPUT:
     261                    rc = VBoxServiceControlHandleCmdGetOutput(g_GuestControlSvcClientID, uNumParms);
     262                    break;
     263
    198264                default:
    199                     VBoxServiceVerbose(3, "Control: Unsupported message from host! Msg=%ld\n", uMsg);
     265                    VBoxServiceVerbose(3, "Control: Unsupported message from host! Msg=%u\n", uMsg);
    200266                    /* Don't terminate here; just wait for the next message. */
    201267                    break;
    202268            }
     269
     270            if (RT_FAILURE(rc))
     271                VBoxServiceVerbose(3, "Control: Message was processed with rc=%Rrc\n", rc);
    203272        }
    204273
     
    252321            int rc2 = RTThreadWait(pNode->Thread, 30 * 1000 /* Wait 30 seconds max. */, NULL);
    253322            if (RT_FAILURE(rc2))
    254                 VBoxServiceError("Control: Thread (PID: %u) failed to stop; rc2=%Rrc\n", pNode->uPID, rc2);
    255         }
    256         VBoxServiceControlExecDestroyThreadData(pNode);
     323                VBoxServiceError("Control: Thread failed to stop; rc2=%Rrc\n", rc2);
     324        }
     325
     326        /* Destroy thread specific data. */
     327        switch (pNode->enmType)
     328        {
     329            case VBoxServiceCtrlThreadDataExec:
     330                VBoxServiceControlExecDestroyThreadData((PVBOXSERVICECTRLTHREADDATAEXEC)pNode->pvData);
     331                break;
     332
     333            default:
     334                break;
     335        }
    257336    }
    258337
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlExec.cpp

    r28463 r28557  
    145145 *
    146146 * @returns IPRT status code from client send.
     147 * @param   pThread             The thread specific data.
    147148 * @param   hPollSet            The polling set.
    148149 * @param   fPollEvt            The event mask returned by RTPollNoResume.
     
    154155 * @todo    Put the last 4 parameters into a struct!
    155156 */
    156 static int VBoxServiceControlExecProcHandleOutputEvent(RTPOLLSET hPollSet, uint32_t fPollEvt, PRTPIPE phPipeR,
     157static int VBoxServiceControlExecProcHandleOutputEvent(PVBOXSERVICECTRLTHREAD pThread,
     158                                                       RTPOLLSET hPollSet, uint32_t fPollEvt, PRTPIPE phPipeR,
    157159                                                       uint32_t *puCrc32 , uint32_t uHandleId)
    158160{
     
    163165     */
    164166    int rc = VINF_SUCCESS;
    165 
    166     char    abBuf[_64K];
    167167    size_t  cbRead;
    168     int     rc2 = RTPipeRead(*phPipeR, abBuf, sizeof(abBuf), &cbRead);
     168    BYTE    abBuf[_64K];
     169
     170    AssertPtr(pThread);
     171    PVBOXSERVICECTRLTHREADDATAEXEC pData = (PVBOXSERVICECTRLTHREADDATAEXEC)pThread->pvData;
     172    AssertPtr(pData);
     173
     174    int rc2 = RTPipeRead(*phPipeR, abBuf, sizeof(abBuf), &cbRead);
    169175    if (RT_SUCCESS(rc2) && cbRead)
    170176    {
    171         Log(("Crc32=%#x ", *puCrc32));
    172 
    173 #if 1
    174             abBuf[cbRead] = '\0';
    175             RTPrintf("%s: %s\n", uHandleId == 1 ? "StdOut: " : "StdErr: ", abBuf);
     177#if 0
     178        /* Only used for "real-time" stdout/stderr data; gets sent immediately (later)! */
     179        rc = VbglR3GuestCtrlExecSendOut(pThread->uClientID, pThread->uContextID,
     180                                        pData->uPID, uHandleId, 0 /* u32Flags */,
     181                                        abBuf, cbRead);
    176182#endif
    177 
    178         /**puCrc32 = RTCrc32Process(*puCrc32, abBuf, cbRead);
    179         Log(("cbRead=%#x Crc32=%#x \n", cbRead, *puCrc32));
    180         Pkt.uCrc32 = RTCrc32Finish(*puCrc32);*/
    181        /* if (g_fDisplayOutput)
    182         {
    183             if (enmHndId == TXSEXECHNDID_STDOUT)
    184                 RTStrmPrintf(g_pStdErr, "%.*s", cbRead, Pkt.abBuf);
    185             else if (enmHndId == TXSEXECHNDID_STDERR)
    186                 RTStrmPrintf(g_pStdErr, "%.*s", cbRead, Pkt.abBuf);
    187         }
    188 
    189         rc = txsReplyInternal(&Pkt.Hdr, pszOpcode, cbRead + sizeof(uint32_t));*/
    190 
    191         /* Make sure we go another poll round in case there was too much data
    192            for the buffer to hold. */
    193         fPollEvt &= RTPOLL_EVT_ERROR;
     183        rc = VBoxServiceControlExecWritePipeBuffer(&pData->stdOut, abBuf, cbRead);
     184        if (RT_SUCCESS(rc))
     185        {
     186            /* Make sure we go another poll round in case there was too much data
     187               for the buffer to hold. */
     188            fPollEvt &= RTPOLL_EVT_ERROR;
     189        }
    194190    }
    195191    else if (RT_FAILURE(rc2))
     
    254250                                                      || hStdOutR   != NIL_RTPIPE
    255251                                                      || hStdErrR   != NIL_RTPIPE;
    256     RTMSINTERVAL const  cMsPollBase                 = hStdInW != NIL_RTPIPE
     252    RTMSINTERVAL const          cMsPollBase         = hStdInW != NIL_RTPIPE
    257253                                                      ? 100   /* need to poll for input */
    258254                                                      : 1000; /* need only poll for process exit and aborts */
    259     RTMSINTERVAL        cMsPollCur                  = 0;
     255    RTMSINTERVAL                cMsPollCur          = 0;
     256
     257    AssertPtr(pThread);
     258
     259    AssertPtr(pThread);
     260    PVBOXSERVICECTRLTHREADDATAEXEC pData = (PVBOXSERVICECTRLTHREADDATAEXEC)pThread->pvData;
     261    AssertPtr(pData);
    260262
    261263    /* Assign PID to thread data. */
    262     pThread->uPID = hProcess;
     264    pData->uPID = hProcess;
    263265
    264266    /*
     
    266268     * and that it's now OK to send input to the process.
    267269     */
    268     AssertPtr(pThread);
    269270    VBoxServiceVerbose(3, "Control: Process started: PID=%u, CID=%u\n",
    270                        pThread->uPID, pThread->uContextID);
     271                       pData->uPID, pThread->uContextID);
    271272    rc = VbglR3GuestCtrlExecReportStatus(pThread->uClientID, pThread->uContextID,
    272                                          pThread->uPID, PROC_STS_STARTED, 0 /* u32Flags */,
     273                                         pData->uPID, PROC_STS_STARTED, 0 /* u32Flags */,
    273274                                         NULL /* pvData */, 0 /* cbData */);
    274275
     
    299300
    300301                case 1 /* TXSEXECHNDID_STDOUT */:
    301                     rc = VBoxServiceControlExecProcHandleOutputEvent(hPollSet, fPollEvt, &hStdOutR, &uStdOutCrc32, 1 /* TXSEXECHNDID_STDOUT */);
     302                    rc = VBoxServiceControlExecProcHandleOutputEvent(pThread, hPollSet, fPollEvt, &hStdOutR, &uStdOutCrc32, 1 /* TXSEXECHNDID_STDOUT */);
    302303                    break;
    303304
    304305                case 2 /*TXSEXECHNDID_STDERR */:
    305                     rc = VBoxServiceControlExecProcHandleOutputEvent(hPollSet, fPollEvt, &hStdErrR, &uStdErrCrc32, 2 /*TXSEXECHNDID_STDERR */);
     306                    rc = VBoxServiceControlExecProcHandleOutputEvent(pThread, hPollSet, fPollEvt, &hStdErrR, &uStdErrCrc32, 2 /*TXSEXECHNDID_STDERR */);
    306307                    break;
    307308
     
    467468
    468469        VBoxServiceVerbose(3, "Control: Process ended: PID=%u, CID=%u, Status=%u, Flags=%u\n",
    469                            pThread->uPID, pThread->uContextID, uStatus, uFlags);
     470                           pData->uPID, pThread->uContextID, uStatus, uFlags);
    470471        rc = VbglR3GuestCtrlExecReportStatus(pThread->uClientID, pThread->uContextID,
    471                                              pThread->uPID, uStatus, uFlags,
     472                                             pData->uPID, uStatus, uFlags,
    472473                                             NULL /* pvData */, 0 /* cbData */);
    473474    }
    474475    RTMemFree(StdInBuf.pch);
    475 
    476476    VBoxServiceVerbose(3, "Control: Process loop ended with rc=%Rrc\n", rc);
    477477    return rc;
     
    529529}
    530530
     531int VBoxServiceControlExecReadPipeBufferContent(PVBOXSERVICECTRLEXECPIPEBUF pBuf,
     532                                                BYTE *pbBuffer, uint32_t cbBuffer, uint32_t *pcbToRead)
     533{
     534    AssertPtr(pcbToRead);
     535
     536// LOCKING
     537
     538    Assert(pBuf->cbOffset >= pBuf->cbRead);
     539    if (*pcbToRead > pBuf->cbOffset - pBuf->cbRead)
     540        *pcbToRead = pBuf->cbOffset - pBuf->cbRead;
     541
     542    if (*pcbToRead > cbBuffer)
     543        *pcbToRead = cbBuffer;
     544
     545    if (*pcbToRead > 0)
     546    {
     547        memcpy(pbBuffer, pBuf->pbData + pBuf->cbRead, *pcbToRead);
     548        pBuf->cbRead += *pcbToRead;
     549    }
     550    else
     551        pbBuffer = NULL;
     552    return VINF_SUCCESS;
     553}
     554
     555int VBoxServiceControlExecWritePipeBuffer(PVBOXSERVICECTRLEXECPIPEBUF pBuf,
     556                                          BYTE *pbData, uint32_t cbData)
     557{
     558    AssertPtr(pBuf);
     559
     560// LOCKING
     561
     562    /** @todo Use RTMemCache or RTMemObj here? */
     563    BYTE *pNewBuf;
     564    while (pBuf->cbSize - pBuf->cbOffset < cbData)
     565    {
     566        pNewBuf = (BYTE*)RTMemRealloc(pBuf->pbData, pBuf->cbSize + _4K);
     567        if (pNewBuf == NULL)
     568            break;
     569        pBuf->cbSize += _4K;
     570        pBuf->pbData = pNewBuf;
     571    }
     572
     573    int rc = VINF_SUCCESS;
     574    if (pBuf->pbData)
     575    {
     576        memcpy(pBuf->pbData + pBuf->cbOffset, pbData, cbData);
     577        pBuf->cbOffset += cbData;
     578        /** @todo Add offset clamping! */
     579    }
     580    else
     581        rc = VERR_NO_MEMORY;
     582    return rc;
     583}
     584
    531585/** Allocates and gives back a thread data struct which then can be used by the worker thread. */
    532586int VBoxServiceControlExecAllocateThreadData(PVBOXSERVICECTRLTHREAD pThread,
     
    540594    AssertPtr(pThread);
    541595
     596    /* General stuff. */   
    542597    pThread->Node.pPrev = NULL;
    543598    pThread->Node.pNext = NULL;
     
    547602    pThread->fStopped = false;
    548603
     604    pThread->uContextID = u32ContextID;
    549605    /* ClientID will be assigned when thread is started! */
    550     pThread->uContextID = u32ContextID;
    551     pThread->uPID = 0; /* Don't have a PID yet. */
    552     pThread->pszCmd = RTStrDup(pszCmd);
    553     pThread->uFlags = uFlags;
    554     pThread->uNumEnvVars = 0;
    555     pThread->uNumArgs = 0; /* Initialize in case of RTGetOptArgvFromString() is failing ... */
     606
     607    /* Specific stuff. */
     608    PVBOXSERVICECTRLTHREADDATAEXEC pData = (PVBOXSERVICECTRLTHREADDATAEXEC)RTMemAlloc(sizeof(VBOXSERVICECTRLTHREADDATAEXEC));
     609    if (pData == NULL)
     610        return VERR_NO_MEMORY;
     611
     612    pData->uPID = 0; /* Don't have a PID yet. */
     613    pData->pszCmd = RTStrDup(pszCmd);
     614    pData->uFlags = uFlags;
     615    pData->uNumEnvVars = 0;
     616    pData->uNumArgs = 0; /* Initialize in case of RTGetOptArgvFromString() is failing ... */
    556617
    557618    /* Prepare argument list. */
    558     int rc = RTGetOptArgvFromString(&pThread->papszArgs, (int*)&pThread->uNumArgs,
     619    int rc = RTGetOptArgvFromString(&pData->papszArgs, (int*)&pData->uNumArgs,
    559620                                    (uNumArgs > 0) ? pszArgs : "", NULL);
    560621    /* Did we get the same result? */
    561     Assert(uNumArgs == pThread->uNumArgs);
     622    Assert(uNumArgs == pData->uNumArgs);
    562623
    563624    if (RT_SUCCESS(rc))
     
    566627        if (uNumEnvVars)
    567628        {
    568             pThread->papszEnv = (char**)RTMemAlloc(uNumEnvVars * sizeof(char*));
    569             AssertPtr(pThread->papszEnv);
    570             pThread->uNumEnvVars = uNumEnvVars;
     629            pData->papszEnv = (char**)RTMemAlloc(uNumEnvVars * sizeof(char*));
     630            AssertPtr(pData->papszEnv);
     631            pData->uNumEnvVars = uNumEnvVars;
    571632
    572633            const char *pcCur = pszEnv;
     
    575636            while (cbLen < cbEnv)
    576637            {
    577                 if (RTStrAPrintf(& pThread->papszEnv[i++], "%s", pcCur) < 0)
     638                if (RTStrAPrintf(&pData->papszEnv[i++], "%s", pcCur) < 0)
    578639                {
    579640                    rc = VERR_NO_MEMORY;
     
    585646        }
    586647
    587         pThread->pszStdIn = RTStrDup(pszStdIn);
    588         pThread->pszStdOut = RTStrDup(pszStdOut);
    589         pThread->pszStdErr = RTStrDup(pszStdErr);
    590         pThread->pszUser = RTStrDup(pszUser);
    591         pThread->pszPassword = RTStrDup(pszPassword);
    592         pThread->uTimeLimitMS = uTimeLimitMS;
    593     }
    594 
    595     /* Adjust time limit value. */
    596     pThread->uTimeLimitMS = (   (uTimeLimitMS == UINT32_MAX)
    597                              || (uTimeLimitMS == 0)) ?
    598                              RT_INDEFINITE_WAIT : uTimeLimitMS;
     648        pData->pszStdIn = RTStrDup(pszStdIn);
     649        pData->pszStdOut = RTStrDup(pszStdOut);
     650        pData->pszStdErr = RTStrDup(pszStdErr);
     651        pData->pszUser = RTStrDup(pszUser);
     652        pData->pszPassword = RTStrDup(pszPassword);
     653        pData->uTimeLimitMS = uTimeLimitMS;
     654
     655        /* Adjust time limit value. */
     656        pData->uTimeLimitMS = (   (uTimeLimitMS == UINT32_MAX)
     657                               || (uTimeLimitMS == 0)) ?
     658                               RT_INDEFINITE_WAIT : uTimeLimitMS;
     659
     660        /* Init buffers. */
     661        pData->stdOut.pbData = NULL;
     662        pData->stdOut.cbSize = 0;
     663        pData->stdOut.cbOffset = 0;
     664        pData->stdOut.cbRead = 0;
     665
     666        pData->stdErr.pbData = NULL;
     667        pData->stdErr.cbSize = 0;
     668        pData->stdErr.cbOffset = 0;
     669        pData->stdErr.cbRead = 0;
     670    }
     671
     672    if (RT_FAILURE(rc))
     673    {
     674        VBoxServiceControlExecDestroyThreadData(pData);
     675    }
     676    else
     677    {
     678        pThread->enmType = VBoxServiceCtrlThreadDataExec;
     679        pThread->pvData = pData;
     680    }
    599681    return rc;
    600682}
    601683
     684void VBoxServiceControlExecDestroyPipeBuffer(PVBOXSERVICECTRLEXECPIPEBUF pBuf)
     685{
     686    if (pBuf)
     687    {
     688        if (pBuf->pbData)
     689            RTMemFree(pBuf->pbData);
     690        pBuf->pbData = NULL;
     691        pBuf->cbSize = 0;
     692        pBuf->cbOffset = 0;
     693        pBuf->cbRead = 0;
     694    }
     695}
     696
    602697/** Frees an allocated thread data structure along with all its allocated parameters. */
    603 void VBoxServiceControlExecDestroyThreadData(PVBOXSERVICECTRLTHREAD pThread)
     698void VBoxServiceControlExecDestroyThreadData(PVBOXSERVICECTRLTHREADDATAEXEC pData)
     699{
     700    if (pData)
     701    {   
     702        RTStrFree(pData->pszCmd);
     703        if (pData->uNumEnvVars)
     704        {
     705            for (uint32_t i = 0; i < pData->uNumEnvVars; i++)
     706                RTStrFree(pData->papszEnv[i]);
     707            RTMemFree(pData->papszEnv);
     708        }
     709        RTGetOptArgvFree(pData->papszArgs);
     710        RTStrFree(pData->pszStdIn);
     711        RTStrFree(pData->pszStdOut);
     712        RTStrFree(pData->pszStdErr);
     713        RTStrFree(pData->pszUser);
     714        RTStrFree(pData->pszPassword);
     715   
     716        VBoxServiceControlExecDestroyPipeBuffer(&pData->stdOut);
     717        VBoxServiceControlExecDestroyPipeBuffer(&pData->stdErr);
     718
     719        RTMemFree(pData);
     720        pData = NULL;
     721    }
     722}
     723
     724DECLCALLBACK(int) VBoxServiceControlExecProcessWorker(PVBOXSERVICECTRLTHREAD pThread)
    604725{
    605726    AssertPtr(pThread);
    606     RTStrFree(pThread->pszCmd);
    607     if (pThread->uNumEnvVars)
    608     {
    609         for (uint32_t i = 0; i < pThread->uNumEnvVars; i++)
    610             RTStrFree(pThread->papszEnv[i]);
    611         RTMemFree(pThread->papszEnv);
    612     }
    613     RTGetOptArgvFree(pThread->papszArgs);
    614     RTStrFree(pThread->pszStdIn);
    615     RTStrFree(pThread->pszStdOut);
    616     RTStrFree(pThread->pszStdErr);
    617     RTStrFree(pThread->pszUser);
    618     RTStrFree(pThread->pszPassword);
    619 }
    620 
    621 DECLCALLBACK(int) VBoxServiceControlExecProcessWorker(PVBOXSERVICECTRLTHREAD pThread)
    622 {
    623     AssertPtr(pThread);
    624 
    625     AssertPtr(pThread);
    626     AssertPtr(pThread->papszArgs);
    627     AssertPtr(pThread->papszEnv);
     727    PVBOXSERVICECTRLTHREADDATAEXEC pData = (PVBOXSERVICECTRLTHREADDATAEXEC)pThread->pvData;
     728    AssertPtr(pData);
    628729
    629730    /*
     
    632733     */
    633734    RTThreadUserSignal(RTThreadSelf());
    634     VBoxServiceVerbose(3, "Control: Thread of process \"%s\" started\n", pThread->pszCmd);
     735    VBoxServiceVerbose(3, "Control: Thread of process \"%s\" started\n", pData->pszCmd);
    635736
    636737    int rc = VbglR3GuestCtrlConnect(&pThread->uClientID);
     
    649750    {
    650751        size_t i;
    651         for (i = 0; i < pThread->uNumEnvVars; i++)
    652         {
    653             rc = RTEnvPutEx(hEnv, pThread->papszEnv[i]);
     752        for (i = 0; i < pData->uNumEnvVars && pData->papszEnv; i++)
     753        {
     754            rc = RTEnvPutEx(hEnv, pData->papszEnv[i]);
    654755            if (RT_FAILURE(rc))
    655756                break;
     
    695796                            {
    696797                                RTPROCESS hProcess;
    697                                 rc = RTProcCreateEx(pThread->pszCmd, pThread->papszArgs, hEnv, pThread->uFlags,
     798                                rc = RTProcCreateEx(pData->pszCmd, pData->papszArgs, hEnv, pData->uFlags,
    698799                                                    phStdIn, phStdOut, phStdErr,
    699                                                     strlen(pThread->pszUser) ? pThread->pszUser : NULL,
    700                                                     strlen(pThread->pszUser) && strlen(pThread->pszPassword) ? pThread->pszPassword : NULL,
     800                                                    strlen(pData->pszUser) ? pData->pszUser : NULL,
     801                                                    strlen(pData->pszUser) && strlen(pData->pszPassword) ? pData->pszPassword : NULL,
    701802                                                    &hProcess);
    702803                                if (RT_SUCCESS(rc))
     
    714815                                    /* Enter the process loop. */
    715816                                    rc = VBoxServiceControlExecProcLoop(pThread,
    716                                                                         hProcess, pThread->uTimeLimitMS, hPollSet,
     817                                                                        hProcess, pData->uTimeLimitMS, hPollSet,
    717818                                                                        hStdInW, hStdOutR, hStdErrR);
    718819
     
    732833                                else /* Something went wrong; report error! */
    733834                                {
    734                                     int rc2 = VbglR3GuestCtrlExecReportStatus(pThread->uClientID, pThread->uContextID, pThread->uPID,
     835                                    int rc2 = VbglR3GuestCtrlExecReportStatus(pThread->uClientID, pThread->uContextID, pData->uPID,
    735836                                                                              PROC_STS_ERROR, rc,
    736837                                                                              NULL /* pvData */, 0 /* cbData */);
     
    756857    VbglR3GuestCtrlDisconnect(pThread->uClientID);
    757858    VBoxServiceVerbose(3, "Control: Thread of process \"%s\" (PID: %u) ended with rc=%Rrc\n",
    758                        pThread->pszCmd, pThread->uPID, rc);
     859                       pData->pszCmd, pData->uPID, rc);
    759860    return rc;
    760861}
     
    807908                else
    808909                {
     910                    pThread->fStarted = true;
    809911                    /*rc =*/ RTListAppend(&g_GuestControlExecThreads, &pThread->Node);
    810912                }
     
    812914
    813915            if (RT_FAILURE(rc))
    814                 VBoxServiceControlExecDestroyThreadData(pThread);
     916                VBoxServiceControlExecDestroyThreadData((PVBOXSERVICECTRLTHREADDATAEXEC)pThread->pvData);
    815917        }
    816918        if (RT_FAILURE(rc))
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceInternal.h

    r28434 r28557  
    130130
    131131#ifdef VBOX_WITH_GUEST_CONTROL
    132 /* Structure for holding thread relevant data. */
    133 typedef struct
    134 {
    135     /** Node. */
    136     RTLISTNODE                 Node;
    137     /** The worker thread. */
    138     RTTHREAD                   Thread;
    139     /** Shutdown indicator. */
    140     bool volatile              fShutdown;
    141     /** Indicator set by the service thread exiting. */
    142     bool volatile              fStopped;
    143     /** Whether the service was started or not. */
    144     bool                       fStarted;
    145     /** @todo */
    146     uint32_t  uClientID;
    147     uint32_t  uContextID;
     132enum VBOXSERVICECTRLTHREADDATATYPE
     133{
     134    VBoxServiceCtrlThreadDataUnknown = 0,
     135    VBoxServiceCtrlThreadDataExec = 1
     136};
     137
     138typedef struct
     139{
     140    BYTE     *pbData;
     141    uint32_t  cbSize;
     142    uint32_t  cbOffset;
     143    uint32_t  cbRead;
     144} VBOXSERVICECTRLEXECPIPEBUF;
     145/** Pointer to thread data. */
     146typedef VBOXSERVICECTRLEXECPIPEBUF *PVBOXSERVICECTRLEXECPIPEBUF;
     147
     148/* Structure for holding guest exection relevant data. */
     149typedef struct
     150{
    148151    uint32_t  uPID;
    149152    char     *pszCmd;
     
    159162    char     *pszPassword;
    160163    uint32_t  uTimeLimitMS;
     164
     165    VBOXSERVICECTRLEXECPIPEBUF stdOut;
     166    VBOXSERVICECTRLEXECPIPEBUF stdErr;
     167
     168} VBOXSERVICECTRLTHREADDATAEXEC;
     169/** Pointer to thread data. */
     170typedef VBOXSERVICECTRLTHREADDATAEXEC *PVBOXSERVICECTRLTHREADDATAEXEC;
     171
     172/* Structure for holding thread relevant data. */
     173typedef struct
     174{
     175    /** Node. */
     176    RTLISTNODE                      Node;
     177    /** The worker thread. */
     178    RTTHREAD                        Thread;
     179    /** Shutdown indicator. */
     180    bool volatile                   fShutdown;
     181    /** Indicator set by the service thread exiting. */
     182    bool volatile                   fStopped;
     183    /** Whether the service was started or not. */
     184    bool                            fStarted;
     185    /** Client ID. */
     186    uint32_t                        uClientID;
     187    /** Context ID. */
     188    uint32_t                        uContextID;
     189    /** Type of thread.  See VBOXSERVICECTRLTHREADDATATYPE for more info. */
     190    VBOXSERVICECTRLTHREADDATATYPE   enmType;
     191    /** Pointer to actual thread data, depending on enmType. */
     192    void                           *pvData;
    161193} VBOXSERVICECTRLTHREAD;
    162194/** Pointer to thread data. */
     
    236268                                         const char *pszStdIn, const char *pszStdOut, const char *pszStdErr,
    237269                                         const char *pszUser, const char *pszPassword, uint32_t uTimeLimitMS);
    238 extern void VBoxServiceControlExecDestroyThreadData(PVBOXSERVICECTRLTHREAD pThread);
     270extern void VBoxServiceControlExecDestroyThreadData(PVBOXSERVICECTRLTHREADDATAEXEC pThread);
     271extern int VBoxServiceControlExecReadPipeBufferContent(PVBOXSERVICECTRLEXECPIPEBUF pBuf,
     272                                                       BYTE *pbBuffer, uint32_t cbBuffer, uint32_t *pcbToRead);
     273extern int VBoxServiceControlExecWritePipeBuffer(PVBOXSERVICECTRLEXECPIPEBUF pBuf,
     274                                                 BYTE *pbData, uint32_t cbData);
    239275#endif
    240276
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp

    r28464 r28557  
    6363{
    6464    RTPrintf("VBoxManage guestcontrol     execute <vmname>|<uuid>\n"
    65              "                            <path to program> [--arguments \"<arguments>\"] [--environment \"NAME=VALUE NAME=VALUE\"]\n"
     65             "                            <path to program> [--arguments \"<arguments>\"] [--environment \"<NAME=VALUE NAME=VALUE>\"]\n"
    6666             "                            [--flags <flags>] [--timeout <msec>] [--username <name> [--password <password>]]\n"
    6767             "                            [--verbose] [--wait-for exit]\n"
     
    187187                    waitForExit = true;
    188188                else if (!strcmp(a->argv[i + 1], "stdout"))
     189                {
     190                    waitForExit = true;
    189191                    waitForStdOut = true;
     192                }
    190193                else if (!strcmp(a->argv[i + 1], "stderr"))
     194                {
     195                    waitForExit = true;
    191196                    waitForStdErr = true;
     197                }
    192198                else
    193199                    usageOK = false;
     
    324330                            SafeArray<BYTE> aOutputData;
    325331                            ULONG cbOutputData;
    326                             CHECK_ERROR_BREAK(guest, GetProcessOutput(uPID, 0 /* aFlags */, _512K, ComSafeArrayAsOutParam(aOutputData)));
     332                            CHECK_ERROR_BREAK(guest, GetProcessOutput(uPID, 0 /* aFlags */,
     333                                                                      uTimeoutMS, _64K, ComSafeArrayAsOutParam(aOutputData)));
    327334                            cbOutputData = aOutputData.size();
    328335                            if (cbOutputData == 0)
  • trunk/src/VBox/HostServices/GuestControl/Makefile.kmk

    r27897 r28557  
    2424
    2525# Include sub-makefile(s).
    26 include $(PATH_SUB_CURRENT)/testcase/Makefile.kmk
     26# include $(PATH_SUB_CURRENT)/testcase/Makefile.kmk
    2727
    2828#
  • trunk/src/VBox/HostServices/GuestControl/service.cpp

    r28286 r28557  
    235235    }
    236236private:
    237     int paramBufferAllocate(PVBOXGUESTCTRPARAMBUFFER pBuf, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
     237    int paramBufferAllocate(PVBOXGUESTCTRPARAMBUFFER pBuf, uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
    238238    void paramBufferFree(PVBOXGUESTCTRPARAMBUFFER pBuf);
    239239    int paramBufferAssign(PVBOXGUESTCTRPARAMBUFFER pBuf, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
     
    269269/** @todo Write some nice doc headers! */
    270270/* Stores a HGCM request in an internal buffer (pEx). Needs to be freed later using execBufferFree(). */
    271 int Service::paramBufferAllocate(PVBOXGUESTCTRPARAMBUFFER pBuf, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
     271int Service::paramBufferAllocate(PVBOXGUESTCTRPARAMBUFFER pBuf, uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
    272272{
    273273    AssertPtr(pBuf);
     
    281281    if (RT_SUCCESS(rc))
    282282    {
     283        pBuf->uMsg = uMsg;
    283284        pBuf->uParmCount = cParms;
    284285        pBuf->pParms = (VBOXHGCMSVCPARM*)RTMemAlloc(sizeof(VBOXHGCMSVCPARM) * pBuf->uParmCount);
     
    436437             if (uParmCount > cParms)
    437438             {
    438                 uint32_t uCmd = 0;
    439                 if (uParmCount)
    440                     curCmd.parmBuf.pParms[0].getUInt32(&uCmd);
    441 
    442                  paParms[0].setUInt32(/*uCmd*/ 1); /* Message ID */
     439                 paParms[0].setUInt32(curCmd.parmBuf.uMsg); /* Message ID */
    443440                 paParms[1].setUInt32(uParmCount); /* Required parameters for message */
    444441
     
    508505                                  (void *)(&data), sizeof(data));
    509506    }
     507    else if (   eFunction == GUEST_EXEC_SEND_OUTPUT
     508             && cParms    == 5)
     509    {
     510        HOSTEXECOUTCALLBACKDATA data;
     511        data.hdr.u32Magic = HOSTEXECOUTCALLBACKDATAMAGIC;
     512        paParms[0].getUInt32(&data.hdr.u32ContextID);
     513
     514        paParms[1].getUInt32(&data.u32PID);
     515        paParms[2].getUInt32(&data.u32HandleId);
     516        paParms[3].getUInt32(&data.u32Flags);
     517        paParms[4].getPointer(&data.pvData, &data.cbData);
     518
     519        if (mpfnHostCallback)
     520            rc = mpfnHostCallback(mpvHostData, eFunction,
     521                                  (void *)(&data), sizeof(data));
     522    }
    510523    else
    511524        rc = VERR_NOT_SUPPORTED;
     
    519532
    520533    HostCmd newCmd;
    521     rc = paramBufferAllocate(&newCmd.parmBuf, cParms, paParms);
     534    rc = paramBufferAllocate(&newCmd.parmBuf, eFunction, cParms, paParms);
    522535    if (RT_SUCCESS(rc))
    523536    {
     
    565578                break;
    566579
    567             /* The guest notifies the host that some output at stdout is available. */
    568             case GUEST_EXEC_SEND_STDOUT:
    569                 LogFlowFunc(("GUEST_EXEC_SEND_STDOUT\n"));
    570                 break;
    571 
    572             /* The guest notifies the host that some output at stderr is available. */
    573             case GUEST_EXEC_SEND_STDERR:
    574                 LogFlowFunc(("GUEST_EXEC_SEND_STDERR\n"));
     580            /* The guest notifies the host that some output at stdout/stderr is available. */
     581            case GUEST_EXEC_SEND_OUTPUT:
     582                LogFlowFunc(("GUEST_EXEC_SEND_OUTPUT\n"));
     583                rc = notifyHost(eFunction, cParms, paParms);
    575584                break;
    576585
     
    621630
    622631            /* The host wants to send something to the guest's stdin pipe. */
    623             case HOST_EXEC_SEND_STDIN:
    624                 LogFlowFunc(("HOST_EXEC_SEND_STDIN\n"));
    625                 break;
    626 
    627             case HOST_EXEC_GET_STATUS:
    628                 LogFlowFunc(("HOST_EXEC_GET_STATUS\n"));
     632            case HOST_EXEC_SET_INPUT:
     633                LogFlowFunc(("HOST_EXEC_SET_INPUT\n"));
     634                break;
     635
     636            case HOST_EXEC_GET_OUTPUT:
     637                LogFlowFunc(("HOST_EXEC_GET_OUTPUT\n"));
     638                rc = processCmd(eFunction, cParms, paParms);
    629639                break;
    630640
  • trunk/src/VBox/Main/GuestImpl.cpp

    r28529 r28557  
    485485        rc = pGuest->notifyCtrlExec(u32Function, pCBData);
    486486    }
     487    else if (u32Function == GUEST_EXEC_SEND_OUTPUT)
     488    {
     489        LogFlowFunc(("GUEST_EXEC_SEND_OUTPUT\n"));
     490
     491        PHOSTEXECOUTCALLBACKDATA pCBData = reinterpret_cast<PHOSTEXECOUTCALLBACKDATA>(pvParms);
     492        AssertPtr(pCBData);
     493        AssertReturn(sizeof(HOSTEXECOUTCALLBACKDATA) == cbParms, VERR_INVALID_PARAMETER);
     494        AssertReturn(HOSTEXECOUTCALLBACKDATAMAGIC == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     495
     496        rc = pGuest->notifyCtrlExecOut(u32Function, pCBData);
     497    }
    487498    else
    488499        rc = VERR_NOT_SUPPORTED;
     
    498509
    499510    AssertPtr(pData);
    500     CallbackListIter it = getCtrlCallbackContext(pData->hdr.u32ContextID);
     511    CallbackListIter it = getCtrlCallbackContextByID(pData->hdr.u32ContextID);
    501512    if (it != mCallbackList.end())
    502513    {
     514        Assert(!it->bCalled);
    503515        PHOSTEXECCALLBACKDATA pCBData = (HOSTEXECCALLBACKDATA*)it->pvData;
    504516        AssertPtr(pCBData);
     
    555567        ASMAtomicWriteBool(&it->bCalled, true);
    556568    }
     569    else
     570        LogFlowFunc(("Unexpected callback (magic=%u, context ID=%u) arrived\n", pData->hdr.u32Magic, pData->hdr.u32ContextID));
    557571    LogFlowFuncLeave();
    558572    return rc;
    559573}
    560574
    561 Guest::CallbackListIter Guest::getCtrlCallbackContext(uint32_t u32ContextID)
    562 {
     575/* Notifier function for control execution stuff. */
     576int Guest::notifyCtrlExecOut(uint32_t                 u32Function,
     577                             PHOSTEXECOUTCALLBACKDATA pData)
     578{
     579    LogFlowFuncEnter();
     580    int rc = VINF_SUCCESS;
     581
     582    AssertPtr(pData);
     583    CallbackListIter it = getCtrlCallbackContextByID(pData->hdr.u32ContextID);
     584    if (it != mCallbackList.end())
     585    {
     586        Assert(!it->bCalled);
     587        PHOSTEXECOUTCALLBACKDATA pCBData = (HOSTEXECOUTCALLBACKDATA*)it->pvData;
     588        AssertPtr(pCBData);
     589
     590        pCBData->u32PID = pData->u32PID;
     591        pCBData->u32HandleId = pData->u32HandleId;
     592        pCBData->u32Flags = pData->u32Flags;
     593       
     594        /* Allocate data buffer and copy it */
     595        if (pData->cbData && pData->pvData)
     596        {
     597            pCBData->pvData = RTMemAlloc(pData->cbData);
     598            AssertPtr(pCBData->pvData);
     599            memcpy(pCBData->pvData, pData->pvData, pData->cbData);
     600            pCBData->cbData = pData->cbData;
     601        }
     602
     603        ASMAtomicWriteBool(&it->bCalled, true);
     604    }
     605    else
     606        LogFlowFunc(("Unexpected callback (magic=%u, context ID=%u) arrived\n", pData->hdr.u32Magic, pData->hdr.u32ContextID));
     607    LogFlowFuncLeave();
     608    return rc;
     609}
     610
     611Guest::CallbackListIter Guest::getCtrlCallbackContextByID(uint32_t u32ContextID)
     612{
     613    /** @todo Maybe use a map instead of list for fast context lookup. */
    563614    CallbackListIter it;
    564615    for (it = mCallbackList.begin(); it != mCallbackList.end(); it++)
    565616    {
    566617        if (it->mContextID == u32ContextID)
     618            return (it);
     619    }
     620    return it;
     621}
     622
     623Guest::CallbackListIter Guest::getCtrlCallbackContextByPID(uint32_t u32PID)
     624{
     625    /** @todo Maybe use a map instead of list for fast context lookup. */
     626    CallbackListIter it;
     627    for (it = mCallbackList.begin(); it != mCallbackList.end(); it++)
     628    {
     629        PHOSTEXECCALLBACKDATA pCBData = (HOSTEXECCALLBACKDATA*)it->pvData;
     630        if (pCBData && pCBData->u32PID == u32PID)
    567631            return (it);
    568632    }
     
    755819                 * get the PID.
    756820                 */
    757                 CallbackListIter it = getCtrlCallbackContext(uContextID);
     821                CallbackListIter it = getCtrlCallbackContextByID(uContextID);
    758822                uint64_t u64Started = RTTimeMilliTS();
    759823                do
     
    854918}
    855919
    856 STDMETHODIMP Guest::GetProcessOutput(ULONG aPID, ULONG aFlags, ULONG64 aSize, ComSafeArrayOut(BYTE, aData))
     920STDMETHODIMP Guest::GetProcessOutput(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, ULONG64 aSize, ComSafeArrayOut(BYTE, aData))
    857921{
    858922#ifndef VBOX_WITH_GUEST_CONTROL
     
    861925    using namespace guestControl;
    862926
    863     NOREF(aPID);
    864     NOREF(aFlags);
    865     NOREF(aSize);
    866     NOREF(aData);
    867 
    868927    HRESULT rc = S_OK;
    869928
    870     size_t cbData = (size_t)RT_MIN(aSize, _1K);
     929    /* Search for existing PID. */
     930    PHOSTEXECOUTCALLBACKDATA pData = (HOSTEXECOUTCALLBACKDATA*)RTMemAlloc(sizeof(HOSTEXECOUTCALLBACKDATA));
     931    AssertPtr(pData);
     932    uint32_t uContextID = addCtrlCallbackContext(pData, sizeof(HOSTEXECOUTCALLBACKDATA), NULL /* pProgress */);
     933    Assert(uContextID > 0);
     934
     935    size_t cbData = (size_t)RT_MIN(aSize, _64K);
    871936    com::SafeArray<BYTE> outputData(cbData);
    872937
    873     if (FAILED(rc))
    874         outputData.resize(0);
    875     outputData.detachTo(ComSafeArrayOutArg(aData));
    876 
     938    VBOXHGCMSVCPARM paParms[5];
     939    int i = 0;
     940    paParms[i++].setUInt32(uContextID);
     941    paParms[i++].setUInt32(aPID);
     942    paParms[i++].setUInt32(aFlags); /** @todo Should represent stdout and/or stderr. */
     943    //paParms[i++].setPointer(outputData.raw(), aSize);
     944
     945    int vrc = VINF_SUCCESS;
     946
     947    /* Forward the information to the VMM device. */
     948    AssertPtr(mParent);
     949    VMMDev *vmmDev = mParent->getVMMDev();
     950    if (vmmDev)
     951    {
     952        LogFlowFunc(("hgcmHostCall numParms=%d\n", i));
     953        vrc = vmmDev->hgcmHostCall("VBoxGuestControlSvc", HOST_EXEC_GET_OUTPUT,
     954                                   i, paParms);
     955    }
     956
     957    if (RT_SUCCESS(vrc))
     958    {
     959        LogFlowFunc(("Waiting for HGCM callback (timeout=%ldms) ...\n", aTimeoutMS));
     960
     961        /*
     962         * Wait for the HGCM low level callback until the process
     963         * has been started (or something went wrong). This is necessary to
     964         * get the PID.
     965         */
     966        CallbackListIter it = getCtrlCallbackContextByID(uContextID);
     967        uint64_t u64Started = RTTimeMilliTS();
     968        do
     969        {
     970            unsigned cMsWait;
     971            if (aTimeoutMS == RT_INDEFINITE_WAIT)
     972                cMsWait = 1000;
     973            else
     974            {
     975                uint64_t cMsElapsed = RTTimeMilliTS() - u64Started;
     976                if (cMsElapsed >= aTimeoutMS)
     977                    break; /* timed out */
     978                cMsWait = RT_MIN(1000, aTimeoutMS - (uint32_t)cMsElapsed);
     979            }
     980            RTThreadSleep(100);
     981        } while (it != mCallbackList.end() && !it->bCalled);
     982
     983        /* Did we get some output? */
     984        PHOSTEXECOUTCALLBACKDATA pData = (HOSTEXECOUTCALLBACKDATA*)it->pvData;
     985        Assert(it->cbData == sizeof(HOSTEXECOUTCALLBACKDATA));
     986        AssertPtr(pData);
     987
     988        if (   it->bCalled
     989            && pData->cbData)
     990        {
     991            /* Do we need to resize the array? */
     992            if (pData->cbData > cbData)
     993                outputData.resize(pData->cbData);
     994
     995            /* Fill output in supplied out buffer. */ 
     996            memcpy(outputData.raw(), pData->pvData, pData->cbData);
     997            outputData.resize(pData->cbData); /* Shrink to fit actual buffer size. */
     998        }
     999        else
     1000            vrc = VERR_NO_DATA; /* This is not an error we want to report to COM. */
     1001
     1002        if (RT_FAILURE(vrc) || FAILED(rc))
     1003            outputData.resize(0);
     1004        outputData.detachTo(ComSafeArrayOutArg(aData));
     1005    }
    8771006    return rc;
    8781007#endif
  • trunk/src/VBox/Main/idl/VirtualBox.xidl

    r28531 r28557  
    83778377  <interface
    83788378     name="IGuest" extends="$unknown"
    8379      uuid="419cb190-a2f1-4beb-af8d-fadc75c6ecf7"
     8379     uuid="4b8f90ce-e8ef-4f07-af1b-b0b85bc07e37"
    83808380     wsmap="managed"
    83818381     >
     
    86138613        </desc>
    86148614      </param>
     8615      <param name="timeoutMS" type="unsigned long" dir="in">
     8616        <desc>
     8617          The maximum timeout value (in msec) to wait for output
     8618          data. Pass 0 for an infinite timeout.
     8619        </desc>
     8620      </param>     
    86158621      <param name="size" type="unsigned long long" dir="in">
    86168622        <desc>
  • trunk/src/VBox/Main/include/GuestImpl.h

    r28448 r28557  
    9797                              IN_BSTR aUserName, IN_BSTR aPassword,
    9898                              ULONG aTimeoutMS, ULONG* aPID, IProgress **aProgress);
    99     STDMETHOD(GetProcessOutput)(ULONG aPID, ULONG aFlags, ULONG64 aSize, ComSafeArrayOut(BYTE, aData));
     99    STDMETHOD(GetProcessOutput)(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, ULONG64 aSize, ComSafeArrayOut(BYTE, aData));
    100100    STDMETHOD(InternalGetStatistics)(ULONG *aCpuUser, ULONG *aCpuKernel, ULONG *aCpuIdle,
    101101                                     ULONG *aMemTotal, ULONG *aMemFree, ULONG *aMemBalloon, ULONG *aMemCache,
     
    140140    /** Handler for guest execution control notifications. */
    141141    int notifyCtrlExec(uint32_t u32Function, PHOSTEXECCALLBACKDATA pData);
    142     CallbackListIter getCtrlCallbackContext(uint32_t u32ContextID);
     142    int notifyCtrlExecOut(uint32_t u32Function, PHOSTEXECOUTCALLBACKDATA pData);
     143    CallbackListIter getCtrlCallbackContextByID(uint32_t u32ContextID);
     144    CallbackListIter getCtrlCallbackContextByPID(uint32_t u32PID);
    143145    void removeCtrlCallbackContext(CallbackListIter it);
    144146    uint32_t addCtrlCallbackContext(void *pvData, uint32_t cbData, Progress* pProgress);
Note: See TracChangeset for help on using the changeset viewer.

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