Changeset 28557 in vbox
- Timestamp:
- Apr 21, 2010 11:18:32 AM (15 years ago)
- svn:sync-xref-src-repo-rev:
- 60367
- Location:
- trunk
- Files:
-
- 12 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/HostServices/GuestControlSvc.h
r28434 r28557 98 98 /** Size of optional data buffer (not used atm). */ 99 99 uint32_t cbData; 100 101 100 } HOSTEXECCALLBACKDATA, *PHOSTEXECCALLBACKDATA; 102 101 102 typedef 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 103 118 enum 104 119 { 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 107 124 }; 108 125 … … 120 137 * Sends input data for stdin to a running process executed by HOST_EXEC_CMD. 121 138 */ 122 HOST_EXEC_SE ND_STDIN= 2,139 HOST_EXEC_SET_INPUT = 2, 123 140 /** 124 141 * Gets the current status of a running process, e.g. 125 142 * new data on stdout/stderr, process terminated etc. 126 143 */ 127 HOST_EXEC_GET_ STATUS= 3144 HOST_EXEC_GET_OUTPUT = 3 128 145 }; 129 146 … … 141 158 * TODO 142 159 */ 143 GUEST_EXEC_SEND_ STDOUT = 3,160 GUEST_EXEC_SEND_OUTPUT = 2, 144 161 /** 145 162 * TODO 146 163 */ 147 GUEST_EXEC_SEND_STDERR = 4, 148 /** 149 * TODO 150 */ 151 GUEST_EXEC_SEND_STATUS = 5 164 GUEST_EXEC_SEND_STATUS = 3 152 165 }; 153 166 … … 162 175 * or starting a program. 163 176 */ 164 GETHOSTMSG_EXEC_ CMD= 1,177 GETHOSTMSG_EXEC_START_PROCESS = 1, 165 178 /** 166 179 * Sends input data for stdin to a running process executed by HOST_EXEC_CMD. 167 180 */ 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 169 187 }; 170 188 … … 220 238 221 239 } VBoxGuestCtrlHGCMMsgExecCmd; 240 241 typedef 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; 222 256 223 257 typedef struct _VBoxGuestCtrlHGCMMsgExecStatus … … 241 275 typedef struct _VBoxGuestCtrlParamBuffer 242 276 { 277 uint32_t uMsg; 243 278 uint32_t uParmCount; 244 279 VBOXHGCMSVCPARM *pParms; -
trunk/include/VBox/VBoxGuestLib.h
r28441 r28557 526 526 char *pszPassword, uint32_t cbPassword, 527 527 uint32_t *puTimeLimit); 528 VBGLR3DECL(int) VbglR3GuestCtrlExecGetHostCmdOutput(uint32_t u32ClientId, uint32_t uNumParms, 529 uint32_t *puContext, uint32_t *puPID, 530 uint32_t *puHandle, uint32_t *puFlags); 528 531 VBGLR3DECL(int) VbglR3GuestCtrlExecReportStatus(uint32_t u32ClientId, 529 532 uint32_t u32Context, … … 533 536 void *pvData, 534 537 uint32_t cbData); 538 VBGLR3DECL(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); 535 545 /** @} */ 536 546 # endif /* VBOX_WITH_GUEST_CONTROL defined */ -
trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGuestCtrl.cpp
r28434 r28557 146 146 * @returns VBox status code. 147 147 * @param u32ClientId The client id returned by VbglR3GuestCtrlConnect(). 148 * @param ppvData149 148 * @param uNumParms 150 149 ** @todo Docs! … … 223 222 224 223 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 */ 234 VBGLR3DECL(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 } 225 271 226 272 … … 262 308 } 263 309 310 311 /** 312 * Sends output (from stdout/stderr) from a running process. 313 * 314 * @returns VBox status code. 315 ** @todo Docs! 316 */ 317 VBGLR3DECL(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 100 100 101 101 102 static int VBoxServiceControlHandleCmd Exec(uint32_t u32ClientId, uint32_t uNumParms)102 static int VBoxServiceControlHandleCmdStartProcess(uint32_t u32ClientId, uint32_t uNumParms) 103 103 { 104 104 uint32_t uContextID; … … 142 142 if (RT_FAILURE(rc)) 143 143 { 144 VBoxServiceError("Control: Failed to retrieve exec utioncommand! Error: %Rrc\n", rc);144 VBoxServiceError("Control: Failed to retrieve exec start command! Error: %Rrc\n", rc); 145 145 } 146 146 else … … 150 150 szStdIn, szStdOut, szStdErr, 151 151 szUser, szPassword, uTimeLimitMS); 152 } 153 return rc; 154 } 155 156 157 static 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! */ 152 213 } 153 214 return rc; … … 176 237 uint32_t uMsg; 177 238 uint32_t uNumParms; 178 VBoxServiceVerbose( 3, "Control: Waiting for host msg ...\n");239 VBoxServiceVerbose(4, "Control: Waiting for host msg ...\n"); 179 240 rc = VbglR3GuestCtrlGetHostMsg(g_GuestControlSvcClientID, &uMsg, &uNumParms, 1000 /* 1s timeout */); 180 241 if (rc == VERR_TOO_MUCH_DATA) … … 190 251 if (RT_SUCCESS(rc)) 191 252 { 253 VBoxServiceVerbose(3, "Control: Msg=%u (%u parms) retrieved\n", uMsg, uNumParms); 192 254 switch(uMsg) 193 255 { 194 case GETHOSTMSG_EXEC_ CMD:195 rc = VBoxServiceControlHandleCmd Exec(g_GuestControlSvcClientID, uNumParms);256 case GETHOSTMSG_EXEC_START_PROCESS: 257 rc = VBoxServiceControlHandleCmdStartProcess(g_GuestControlSvcClientID, uNumParms); 196 258 break; 197 259 260 case GETHOSTMSG_EXEC_GET_OUTPUT: 261 rc = VBoxServiceControlHandleCmdGetOutput(g_GuestControlSvcClientID, uNumParms); 262 break; 263 198 264 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); 200 266 /* Don't terminate here; just wait for the next message. */ 201 267 break; 202 268 } 269 270 if (RT_FAILURE(rc)) 271 VBoxServiceVerbose(3, "Control: Message was processed with rc=%Rrc\n", rc); 203 272 } 204 273 … … 252 321 int rc2 = RTThreadWait(pNode->Thread, 30 * 1000 /* Wait 30 seconds max. */, NULL); 253 322 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 } 257 336 } 258 337 -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlExec.cpp
r28463 r28557 145 145 * 146 146 * @returns IPRT status code from client send. 147 * @param pThread The thread specific data. 147 148 * @param hPollSet The polling set. 148 149 * @param fPollEvt The event mask returned by RTPollNoResume. … … 154 155 * @todo Put the last 4 parameters into a struct! 155 156 */ 156 static int VBoxServiceControlExecProcHandleOutputEvent(RTPOLLSET hPollSet, uint32_t fPollEvt, PRTPIPE phPipeR, 157 static int VBoxServiceControlExecProcHandleOutputEvent(PVBOXSERVICECTRLTHREAD pThread, 158 RTPOLLSET hPollSet, uint32_t fPollEvt, PRTPIPE phPipeR, 157 159 uint32_t *puCrc32 , uint32_t uHandleId) 158 160 { … … 163 165 */ 164 166 int rc = VINF_SUCCESS; 165 166 char abBuf[_64K];167 167 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); 169 175 if (RT_SUCCESS(rc2) && cbRead) 170 176 { 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); 176 182 #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 } 194 190 } 195 191 else if (RT_FAILURE(rc2)) … … 254 250 || hStdOutR != NIL_RTPIPE 255 251 || hStdErrR != NIL_RTPIPE; 256 RTMSINTERVAL const cMsPollBase= hStdInW != NIL_RTPIPE252 RTMSINTERVAL const cMsPollBase = hStdInW != NIL_RTPIPE 257 253 ? 100 /* need to poll for input */ 258 254 : 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); 260 262 261 263 /* Assign PID to thread data. */ 262 p Thread->uPID = hProcess;264 pData->uPID = hProcess; 263 265 264 266 /* … … 266 268 * and that it's now OK to send input to the process. 267 269 */ 268 AssertPtr(pThread);269 270 VBoxServiceVerbose(3, "Control: Process started: PID=%u, CID=%u\n", 270 p Thread->uPID, pThread->uContextID);271 pData->uPID, pThread->uContextID); 271 272 rc = VbglR3GuestCtrlExecReportStatus(pThread->uClientID, pThread->uContextID, 272 p Thread->uPID, PROC_STS_STARTED, 0 /* u32Flags */,273 pData->uPID, PROC_STS_STARTED, 0 /* u32Flags */, 273 274 NULL /* pvData */, 0 /* cbData */); 274 275 … … 299 300 300 301 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 */); 302 303 break; 303 304 304 305 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 */); 306 307 break; 307 308 … … 467 468 468 469 VBoxServiceVerbose(3, "Control: Process ended: PID=%u, CID=%u, Status=%u, Flags=%u\n", 469 p Thread->uPID, pThread->uContextID, uStatus, uFlags);470 pData->uPID, pThread->uContextID, uStatus, uFlags); 470 471 rc = VbglR3GuestCtrlExecReportStatus(pThread->uClientID, pThread->uContextID, 471 p Thread->uPID, uStatus, uFlags,472 pData->uPID, uStatus, uFlags, 472 473 NULL /* pvData */, 0 /* cbData */); 473 474 } 474 475 RTMemFree(StdInBuf.pch); 475 476 476 VBoxServiceVerbose(3, "Control: Process loop ended with rc=%Rrc\n", rc); 477 477 return rc; … … 529 529 } 530 530 531 int 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 555 int 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 531 585 /** Allocates and gives back a thread data struct which then can be used by the worker thread. */ 532 586 int VBoxServiceControlExecAllocateThreadData(PVBOXSERVICECTRLTHREAD pThread, … … 540 594 AssertPtr(pThread); 541 595 596 /* General stuff. */ 542 597 pThread->Node.pPrev = NULL; 543 598 pThread->Node.pNext = NULL; … … 547 602 pThread->fStopped = false; 548 603 604 pThread->uContextID = u32ContextID; 549 605 /* 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 ... */ 556 617 557 618 /* Prepare argument list. */ 558 int rc = RTGetOptArgvFromString(&p Thread->papszArgs, (int*)&pThread->uNumArgs,619 int rc = RTGetOptArgvFromString(&pData->papszArgs, (int*)&pData->uNumArgs, 559 620 (uNumArgs > 0) ? pszArgs : "", NULL); 560 621 /* Did we get the same result? */ 561 Assert(uNumArgs == p Thread->uNumArgs);622 Assert(uNumArgs == pData->uNumArgs); 562 623 563 624 if (RT_SUCCESS(rc)) … … 566 627 if (uNumEnvVars) 567 628 { 568 p Thread->papszEnv = (char**)RTMemAlloc(uNumEnvVars * sizeof(char*));569 AssertPtr(p Thread->papszEnv);570 p Thread->uNumEnvVars = uNumEnvVars;629 pData->papszEnv = (char**)RTMemAlloc(uNumEnvVars * sizeof(char*)); 630 AssertPtr(pData->papszEnv); 631 pData->uNumEnvVars = uNumEnvVars; 571 632 572 633 const char *pcCur = pszEnv; … … 575 636 while (cbLen < cbEnv) 576 637 { 577 if (RTStrAPrintf(& pThread->papszEnv[i++], "%s", pcCur) < 0)638 if (RTStrAPrintf(&pData->papszEnv[i++], "%s", pcCur) < 0) 578 639 { 579 640 rc = VERR_NO_MEMORY; … … 585 646 } 586 647 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 } 599 681 return rc; 600 682 } 601 683 684 void 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 602 697 /** Frees an allocated thread data structure along with all its allocated parameters. */ 603 void VBoxServiceControlExecDestroyThreadData(PVBOXSERVICECTRLTHREAD pThread) 698 void 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 724 DECLCALLBACK(int) VBoxServiceControlExecProcessWorker(PVBOXSERVICECTRLTHREAD pThread) 604 725 { 605 726 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); 628 729 629 730 /* … … 632 733 */ 633 734 RTThreadUserSignal(RTThreadSelf()); 634 VBoxServiceVerbose(3, "Control: Thread of process \"%s\" started\n", p Thread->pszCmd);735 VBoxServiceVerbose(3, "Control: Thread of process \"%s\" started\n", pData->pszCmd); 635 736 636 737 int rc = VbglR3GuestCtrlConnect(&pThread->uClientID); … … 649 750 { 650 751 size_t i; 651 for (i = 0; i < p Thread->uNumEnvVars; i++)652 { 653 rc = RTEnvPutEx(hEnv, p Thread->papszEnv[i]);752 for (i = 0; i < pData->uNumEnvVars && pData->papszEnv; i++) 753 { 754 rc = RTEnvPutEx(hEnv, pData->papszEnv[i]); 654 755 if (RT_FAILURE(rc)) 655 756 break; … … 695 796 { 696 797 RTPROCESS hProcess; 697 rc = RTProcCreateEx(p Thread->pszCmd, pThread->papszArgs, hEnv, pThread->uFlags,798 rc = RTProcCreateEx(pData->pszCmd, pData->papszArgs, hEnv, pData->uFlags, 698 799 phStdIn, phStdOut, phStdErr, 699 strlen(p Thread->pszUser) ? pThread->pszUser : NULL,700 strlen(p Thread->pszUser) && strlen(pThread->pszPassword) ? pThread->pszPassword : NULL,800 strlen(pData->pszUser) ? pData->pszUser : NULL, 801 strlen(pData->pszUser) && strlen(pData->pszPassword) ? pData->pszPassword : NULL, 701 802 &hProcess); 702 803 if (RT_SUCCESS(rc)) … … 714 815 /* Enter the process loop. */ 715 816 rc = VBoxServiceControlExecProcLoop(pThread, 716 hProcess, p Thread->uTimeLimitMS, hPollSet,817 hProcess, pData->uTimeLimitMS, hPollSet, 717 818 hStdInW, hStdOutR, hStdErrR); 718 819 … … 732 833 else /* Something went wrong; report error! */ 733 834 { 734 int rc2 = VbglR3GuestCtrlExecReportStatus(pThread->uClientID, pThread->uContextID, p Thread->uPID,835 int rc2 = VbglR3GuestCtrlExecReportStatus(pThread->uClientID, pThread->uContextID, pData->uPID, 735 836 PROC_STS_ERROR, rc, 736 837 NULL /* pvData */, 0 /* cbData */); … … 756 857 VbglR3GuestCtrlDisconnect(pThread->uClientID); 757 858 VBoxServiceVerbose(3, "Control: Thread of process \"%s\" (PID: %u) ended with rc=%Rrc\n", 758 p Thread->pszCmd, pThread->uPID, rc);859 pData->pszCmd, pData->uPID, rc); 759 860 return rc; 760 861 } … … 807 908 else 808 909 { 910 pThread->fStarted = true; 809 911 /*rc =*/ RTListAppend(&g_GuestControlExecThreads, &pThread->Node); 810 912 } … … 812 914 813 915 if (RT_FAILURE(rc)) 814 VBoxServiceControlExecDestroyThreadData( pThread);916 VBoxServiceControlExecDestroyThreadData((PVBOXSERVICECTRLTHREADDATAEXEC)pThread->pvData); 815 917 } 816 918 if (RT_FAILURE(rc)) -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceInternal.h
r28434 r28557 130 130 131 131 #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; 132 enum VBOXSERVICECTRLTHREADDATATYPE 133 { 134 VBoxServiceCtrlThreadDataUnknown = 0, 135 VBoxServiceCtrlThreadDataExec = 1 136 }; 137 138 typedef struct 139 { 140 BYTE *pbData; 141 uint32_t cbSize; 142 uint32_t cbOffset; 143 uint32_t cbRead; 144 } VBOXSERVICECTRLEXECPIPEBUF; 145 /** Pointer to thread data. */ 146 typedef VBOXSERVICECTRLEXECPIPEBUF *PVBOXSERVICECTRLEXECPIPEBUF; 147 148 /* Structure for holding guest exection relevant data. */ 149 typedef struct 150 { 148 151 uint32_t uPID; 149 152 char *pszCmd; … … 159 162 char *pszPassword; 160 163 uint32_t uTimeLimitMS; 164 165 VBOXSERVICECTRLEXECPIPEBUF stdOut; 166 VBOXSERVICECTRLEXECPIPEBUF stdErr; 167 168 } VBOXSERVICECTRLTHREADDATAEXEC; 169 /** Pointer to thread data. */ 170 typedef VBOXSERVICECTRLTHREADDATAEXEC *PVBOXSERVICECTRLTHREADDATAEXEC; 171 172 /* Structure for holding thread relevant data. */ 173 typedef 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; 161 193 } VBOXSERVICECTRLTHREAD; 162 194 /** Pointer to thread data. */ … … 236 268 const char *pszStdIn, const char *pszStdOut, const char *pszStdErr, 237 269 const char *pszUser, const char *pszPassword, uint32_t uTimeLimitMS); 238 extern void VBoxServiceControlExecDestroyThreadData(PVBOXSERVICECTRLTHREAD pThread); 270 extern void VBoxServiceControlExecDestroyThreadData(PVBOXSERVICECTRLTHREADDATAEXEC pThread); 271 extern int VBoxServiceControlExecReadPipeBufferContent(PVBOXSERVICECTRLEXECPIPEBUF pBuf, 272 BYTE *pbBuffer, uint32_t cbBuffer, uint32_t *pcbToRead); 273 extern int VBoxServiceControlExecWritePipeBuffer(PVBOXSERVICECTRLEXECPIPEBUF pBuf, 274 BYTE *pbData, uint32_t cbData); 239 275 #endif 240 276 -
trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
r28464 r28557 63 63 { 64 64 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" 66 66 " [--flags <flags>] [--timeout <msec>] [--username <name> [--password <password>]]\n" 67 67 " [--verbose] [--wait-for exit]\n" … … 187 187 waitForExit = true; 188 188 else if (!strcmp(a->argv[i + 1], "stdout")) 189 { 190 waitForExit = true; 189 191 waitForStdOut = true; 192 } 190 193 else if (!strcmp(a->argv[i + 1], "stderr")) 194 { 195 waitForExit = true; 191 196 waitForStdErr = true; 197 } 192 198 else 193 199 usageOK = false; … … 324 330 SafeArray<BYTE> aOutputData; 325 331 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))); 327 334 cbOutputData = aOutputData.size(); 328 335 if (cbOutputData == 0) -
trunk/src/VBox/HostServices/GuestControl/Makefile.kmk
r27897 r28557 24 24 25 25 # Include sub-makefile(s). 26 include $(PATH_SUB_CURRENT)/testcase/Makefile.kmk26 # include $(PATH_SUB_CURRENT)/testcase/Makefile.kmk 27 27 28 28 # -
trunk/src/VBox/HostServices/GuestControl/service.cpp
r28286 r28557 235 235 } 236 236 private: 237 int paramBufferAllocate(PVBOXGUESTCTRPARAMBUFFER pBuf, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);237 int paramBufferAllocate(PVBOXGUESTCTRPARAMBUFFER pBuf, uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 238 238 void paramBufferFree(PVBOXGUESTCTRPARAMBUFFER pBuf); 239 239 int paramBufferAssign(PVBOXGUESTCTRPARAMBUFFER pBuf, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); … … 269 269 /** @todo Write some nice doc headers! */ 270 270 /* 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[])271 int Service::paramBufferAllocate(PVBOXGUESTCTRPARAMBUFFER pBuf, uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 272 272 { 273 273 AssertPtr(pBuf); … … 281 281 if (RT_SUCCESS(rc)) 282 282 { 283 pBuf->uMsg = uMsg; 283 284 pBuf->uParmCount = cParms; 284 285 pBuf->pParms = (VBOXHGCMSVCPARM*)RTMemAlloc(sizeof(VBOXHGCMSVCPARM) * pBuf->uParmCount); … … 436 437 if (uParmCount > cParms) 437 438 { 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 */ 443 440 paParms[1].setUInt32(uParmCount); /* Required parameters for message */ 444 441 … … 508 505 (void *)(&data), sizeof(data)); 509 506 } 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 } 510 523 else 511 524 rc = VERR_NOT_SUPPORTED; … … 519 532 520 533 HostCmd newCmd; 521 rc = paramBufferAllocate(&newCmd.parmBuf, cParms, paParms);534 rc = paramBufferAllocate(&newCmd.parmBuf, eFunction, cParms, paParms); 522 535 if (RT_SUCCESS(rc)) 523 536 { … … 565 578 break; 566 579 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); 575 584 break; 576 585 … … 621 630 622 631 /* 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); 629 639 break; 630 640 -
trunk/src/VBox/Main/GuestImpl.cpp
r28529 r28557 485 485 rc = pGuest->notifyCtrlExec(u32Function, pCBData); 486 486 } 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 } 487 498 else 488 499 rc = VERR_NOT_SUPPORTED; … … 498 509 499 510 AssertPtr(pData); 500 CallbackListIter it = getCtrlCallbackContext (pData->hdr.u32ContextID);511 CallbackListIter it = getCtrlCallbackContextByID(pData->hdr.u32ContextID); 501 512 if (it != mCallbackList.end()) 502 513 { 514 Assert(!it->bCalled); 503 515 PHOSTEXECCALLBACKDATA pCBData = (HOSTEXECCALLBACKDATA*)it->pvData; 504 516 AssertPtr(pCBData); … … 555 567 ASMAtomicWriteBool(&it->bCalled, true); 556 568 } 569 else 570 LogFlowFunc(("Unexpected callback (magic=%u, context ID=%u) arrived\n", pData->hdr.u32Magic, pData->hdr.u32ContextID)); 557 571 LogFlowFuncLeave(); 558 572 return rc; 559 573 } 560 574 561 Guest::CallbackListIter Guest::getCtrlCallbackContext(uint32_t u32ContextID) 562 { 575 /* Notifier function for control execution stuff. */ 576 int 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 611 Guest::CallbackListIter Guest::getCtrlCallbackContextByID(uint32_t u32ContextID) 612 { 613 /** @todo Maybe use a map instead of list for fast context lookup. */ 563 614 CallbackListIter it; 564 615 for (it = mCallbackList.begin(); it != mCallbackList.end(); it++) 565 616 { 566 617 if (it->mContextID == u32ContextID) 618 return (it); 619 } 620 return it; 621 } 622 623 Guest::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) 567 631 return (it); 568 632 } … … 755 819 * get the PID. 756 820 */ 757 CallbackListIter it = getCtrlCallbackContext (uContextID);821 CallbackListIter it = getCtrlCallbackContextByID(uContextID); 758 822 uint64_t u64Started = RTTimeMilliTS(); 759 823 do … … 854 918 } 855 919 856 STDMETHODIMP Guest::GetProcessOutput(ULONG aPID, ULONG aFlags, ULONG 64 aSize, ComSafeArrayOut(BYTE, aData))920 STDMETHODIMP Guest::GetProcessOutput(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, ULONG64 aSize, ComSafeArrayOut(BYTE, aData)) 857 921 { 858 922 #ifndef VBOX_WITH_GUEST_CONTROL … … 861 925 using namespace guestControl; 862 926 863 NOREF(aPID);864 NOREF(aFlags);865 NOREF(aSize);866 NOREF(aData);867 868 927 HRESULT rc = S_OK; 869 928 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); 871 936 com::SafeArray<BYTE> outputData(cbData); 872 937 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 } 877 1006 return rc; 878 1007 #endif -
trunk/src/VBox/Main/idl/VirtualBox.xidl
r28531 r28557 8377 8377 <interface 8378 8378 name="IGuest" extends="$unknown" 8379 uuid="4 19cb190-a2f1-4beb-af8d-fadc75c6ecf7"8379 uuid="4b8f90ce-e8ef-4f07-af1b-b0b85bc07e37" 8380 8380 wsmap="managed" 8381 8381 > … … 8613 8613 </desc> 8614 8614 </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> 8615 8621 <param name="size" type="unsigned long long" dir="in"> 8616 8622 <desc> -
trunk/src/VBox/Main/include/GuestImpl.h
r28448 r28557 97 97 IN_BSTR aUserName, IN_BSTR aPassword, 98 98 ULONG aTimeoutMS, ULONG* aPID, IProgress **aProgress); 99 STDMETHOD(GetProcessOutput)(ULONG aPID, ULONG aFlags, ULONG 64 aSize, ComSafeArrayOut(BYTE, aData));99 STDMETHOD(GetProcessOutput)(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, ULONG64 aSize, ComSafeArrayOut(BYTE, aData)); 100 100 STDMETHOD(InternalGetStatistics)(ULONG *aCpuUser, ULONG *aCpuKernel, ULONG *aCpuIdle, 101 101 ULONG *aMemTotal, ULONG *aMemFree, ULONG *aMemBalloon, ULONG *aMemCache, … … 140 140 /** Handler for guest execution control notifications. */ 141 141 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); 143 145 void removeCtrlCallbackContext(CallbackListIter it); 144 146 uint32_t addCtrlCallbackContext(void *pvData, uint32_t cbData, Progress* pProgress);
Note:
See TracChangeset
for help on using the changeset viewer.