Changeset 44963 in vbox for trunk/src/VBox/Additions
- Timestamp:
- Mar 8, 2013 2:44:06 PM (12 years ago)
- Location:
- trunk/src/VBox/Additions/common/VBoxService
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp
r44935 r44963 53 53 * the maximum number of processes is unlimited. */ 54 54 static uint32_t g_uControlProcsMaxKept = 256; 55 #ifdef DEBUG 56 static bool g_fControlDumpStdErr = false; 57 static bool g_fControlDumpStdOut = false; 58 #endif 59 /** List of active guest control threads (VBOXSERVICECTRLTHREAD). */ 60 static RTLISTANCHOR g_lstControlThreadsActive; 61 /** List of inactive guest control threads (VBOXSERVICECTRLTHREAD). */ 62 static RTLISTANCHOR g_lstControlThreadsInactive; 63 /** Critical section protecting g_GuestControlExecThreads. */ 64 static RTCRITSECT g_csControlThreads; 65 /** List of guest control sessions (VBOXSERVICECTRLSESSION). */ 66 RTLISTANCHOR g_lstControlSessions; 55 /** List of guest control session threads (VBOXSERVICECTRLSESSIONTHREAD). 56 * A guest session thread represents a forked guest session process 57 * of VBoxService. */ 58 RTLISTANCHOR g_lstControlSessionThreads; 59 /** The local session object used for handling all session-related stuff. 60 * When using the legacy guest control protocol (< 2), this session runs 61 * under behalf of the VBoxService main process. On newer protocol versions 62 * each session is a forked version of VBoxService using the appropriate 63 * user credentials for opening a guest session. */ 64 VBOXSERVICECTRLSESSION g_Session; 67 65 68 66 /******************************************************************************* … … 71 69 static int gstcntlHandleSessionOpen(PVBGLR3GUESTCTRLHOSTCTX pHostCtx); 72 70 static int gstcntlHandleSessionClose(PVBGLR3GUESTCTRLHOSTCTX pHostCtx); 73 static int gstcntlHandleProcExec(PVBGLR3GUESTCTRLHOSTCTX pHostCtx);74 static int gstcntlHandleProcInput(PVBGLR3GUESTCTRLHOSTCTX pHostCtx, void *pvScratchBuf, size_t cbScratchBuf);75 static int gstcntlHandleProcOutput(PVBGLR3GUESTCTRLHOSTCTX pHostCtx);76 static int gstcntlHandleProcTerminate(PVBGLR3GUESTCTRLHOSTCTX pHostCtx);77 static int gstcntlHandleProcWaitFor(PVBGLR3GUESTCTRLHOSTCTX pHostCtx);78 static int gstcntlReapThreads(void);79 71 static void VBoxServiceControlShutdown(void); 80 static int vboxServiceControlProcessCloseAll(void);81 static int gstcntlStartAllowed(bool *pbAllowed);82 83 #ifdef DEBUG84 static int gstcntlDumpToFile(const char *pszFileName, void *pvBuf, size_t cbBuf)85 {86 AssertPtrReturn(pszFileName, VERR_INVALID_POINTER);87 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);88 89 if (!cbBuf)90 return VINF_SUCCESS;91 92 char szFile[RTPATH_MAX];93 94 int rc = RTPathTemp(szFile, sizeof(szFile));95 if (RT_SUCCESS(rc))96 rc = RTPathAppend(szFile, sizeof(szFile), pszFileName);97 98 if (RT_SUCCESS(rc))99 {100 VBoxServiceVerbose(4, "Dumping %ld bytes to \"%s\"\n", cbBuf, szFile);101 102 RTFILE fh;103 rc = RTFileOpen(&fh, szFile, RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE);104 if (RT_SUCCESS(rc))105 {106 rc = RTFileWrite(fh, pvBuf, cbBuf, NULL /* pcbWritten */);107 RTFileClose(fh);108 }109 }110 111 return rc;112 }113 #endif114 72 115 73 … … 159 117 &g_uControlIntervalMS, 1, UINT32_MAX - 1); 160 118 #ifdef DEBUG 119 else if (!strcmp(argv[*pi], "--control-dump-stdout")) 120 { 121 g_Session.uFlags |= VBOXSERVICECTRLSESSION_FLAG_DUMPSTDOUT; 122 rc = 0; /* Flag this command as parsed. */ 123 } 161 124 else if (!strcmp(argv[*pi], "--control-dump-stderr")) 162 125 { 163 g_fControlDumpStdErr = true; 164 rc = 0; /* Flag this command as parsed. */ 165 } 166 else if (!strcmp(argv[*pi], "--control-dump-stdout")) 167 { 168 g_fControlDumpStdOut = true; 126 g_Session.uFlags |= VBOXSERVICECTRLSESSION_FLAG_DUMPSTDERR; 169 127 rc = 0; /* Flag this command as parsed. */ 170 128 } … … 197 155 198 156 /* Init lists. */ 199 RTListInit(&g_lstControlThreadsActive); 200 RTListInit(&g_lstControlThreadsInactive); 201 RTListInit(&g_lstControlSessions); 202 203 /* Init critical section for protecting the thread lists. */ 204 rc = RTCritSectInit(&g_csControlThreads); 205 AssertRC(rc); 157 RTListInit(&g_lstControlSessionThreads); 206 158 } 207 159 else … … 275 227 /* Close all opened guest sessions -- all context IDs, sessions etc. 276 228 * are now invalid. */ 277 rc2 = vboxServiceControlProcessCloseAll();229 rc2 = GstCntlSessionCloseAll(&g_Session); 278 230 AssertRC(rc2); 279 231 } … … 293 245 break; 294 246 295 case HOST_EXEC_CMD:296 rc = gstcntlHandleProcExec(&ctxHost);297 break;298 299 case HOST_EXEC_SET_INPUT:300 rc = gstcntlHandleProcInput(&ctxHost,301 pvScratchBuf, cbScratchBuf);302 break;303 304 case HOST_EXEC_GET_OUTPUT:305 rc = gstcntlHandleProcOutput(&ctxHost);306 break;307 308 case HOST_EXEC_TERMINATE:309 rc = gstcntlHandleProcTerminate(&ctxHost);310 break;311 312 case HOST_EXEC_WAIT_FOR:313 rc = gstcntlHandleProcWaitFor(&ctxHost);314 break;315 316 247 default: 317 VBoxServiceVerbose(3, "Unsupported message from host! Msg=%u\n", uMsg);318 /* Don't terminate here; just wait for the next message. */248 rc = GstCntlSessionHandler(&g_Session, uMsg, &ctxHost, 249 pvScratchBuf, cbScratchBuf, pfShutdown); 319 250 break; 320 251 } … … 339 270 340 271 VBoxServiceVerbose(0, "Guest control worker returned with rc=%Rrc\n", rc); 341 return rc;342 }343 344 345 /**346 * Handles starting processes on the guest.347 *348 * @returns IPRT status code.349 * @param uClientID The HGCM client session ID.350 * @param cParms The number of parameters the host is offering.351 */352 static int gstcntlHandleProcExec(PVBGLR3GUESTCTRLHOSTCTX pHostCtx)353 {354 AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);355 356 int rc;357 bool fStartAllowed = false; /* Flag indicating whether starting a process is allowed or not. */358 359 if ( (pHostCtx->uProtocol < 2 && pHostCtx->uNumParms == 11)360 || (pHostCtx->uProtocol >= 2 && pHostCtx->uNumParms == 12)361 )362 {363 VBOXSERVICECTRLPROCSTARTUPINFO proc;364 RT_ZERO(proc);365 366 /* Initialize maximum environment block size -- needed as input367 * parameter to retrieve the stuff from the host. On output this then368 * will contain the actual block size. */369 proc.cbEnv = sizeof(proc.szEnv);370 371 rc = VbglR3GuestCtrlProcGetStart(pHostCtx,372 /* Command */373 proc.szCmd, sizeof(proc.szCmd),374 /* Flags */375 &proc.uFlags,376 /* Arguments */377 proc.szArgs, sizeof(proc.szArgs), &proc.uNumArgs,378 /* Environment */379 proc.szEnv, &proc.cbEnv, &proc.uNumEnvVars,380 /* Credentials; for hosts with VBox < 4.3. */381 proc.szUser, sizeof(proc.szUser),382 proc.szPassword, sizeof(proc.szPassword),383 /* Timelimit */384 &proc.uTimeLimitMS,385 /* Process priority */386 &proc.uPriority,387 /* Process affinity */388 proc.uAffinity, sizeof(proc.uAffinity), &proc.uNumAffinity);389 if (RT_SUCCESS(rc))390 {391 VBoxServiceVerbose(3, "Request to start process szCmd=%s, uFlags=0x%x, szArgs=%s, szEnv=%s, szUser=%s, szPassword=%s, uTimeout=%RU32\n",392 proc.szCmd, proc.uFlags,393 proc.uNumArgs ? proc.szArgs : "<None>",394 proc.uNumEnvVars ? proc.szEnv : "<None>",395 proc.szUser,396 #ifdef DEBUG397 proc.szPassword,398 #else399 "XXX", /* Never show passwords in release mode. */400 #endif401 proc.uTimeLimitMS);402 403 rc = gstcntlReapThreads();404 if (RT_FAILURE(rc))405 VBoxServiceError("Reaping stopped processes failed with rc=%Rrc\n", rc);406 /* Keep going. */407 408 rc = gstcntlStartAllowed(&fStartAllowed);409 if (RT_SUCCESS(rc))410 {411 if (fStartAllowed)412 {413 rc = GstCntlProcessStart(pHostCtx->uContextID, &proc);414 }415 else416 rc = VERR_MAX_PROCS_REACHED; /* Maximum number of processes reached. */417 }418 }419 }420 else421 rc = VERR_NOT_SUPPORTED; /* Unsupported number of parameters. */422 423 /* In case of an error we need to notify the host to not wait forever for our response. */424 if (RT_FAILURE(rc))425 {426 VBoxServiceError("Starting process failed with rc=%Rrc\n", rc);427 428 /*429 * Note: The context ID can be 0 because we mabye weren't able to fetch the command430 * from the host. The host in case has to deal with that!431 */432 int rc2 = VbglR3GuestCtrlProcCbStatus(pHostCtx->uClientID, pHostCtx->uContextID,433 0 /* PID, invalid */,434 PROC_STS_ERROR, rc,435 NULL /* pvData */, 0 /* cbData */);436 if (RT_FAILURE(rc2))437 {438 VBoxServiceError("Error sending start process status to host, rc=%Rrc\n", rc2);439 if (RT_SUCCESS(rc))440 rc = rc2;441 }442 }443 444 return rc;445 }446 447 448 static int gstcntlHandleProcTerminate(PVBGLR3GUESTCTRLHOSTCTX pHostCtx)449 {450 AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);451 452 uint32_t uPID;453 int rc = VbglR3GuestCtrlProcGetTerminate(pHostCtx, &uPID);454 if (RT_SUCCESS(rc))455 {456 PVBOXSERVICECTRLREQUEST pRequest;457 rc = GstCntlProcessRequestAllocEx(&pRequest, VBOXSERVICECTRLREQUEST_PROC_TERM,458 NULL /* pvBuf */, 0 /* cbBuf */, pHostCtx->uContextID);459 if (RT_SUCCESS(rc))460 {461 rc = GstCntlProcessPerform(uPID, pRequest);462 GstCntlProcessRequestFree(pRequest);463 }464 }465 466 return rc;467 }468 469 470 static int gstcntlHandleProcWaitFor(PVBGLR3GUESTCTRLHOSTCTX pHostCtx)471 {472 AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);473 474 uint32_t uPID;475 uint32_t uWaitFlags; uint32_t uTimeoutMS;476 477 int rc = VbglR3GuestCtrlProcGetWaitFor(pHostCtx, &uPID, &uWaitFlags, &uTimeoutMS);478 if (RT_SUCCESS(rc))479 {480 PVBOXSERVICECTRLREQUEST pRequest;481 VBOXSERVICECTRLREQDATA_WAIT_FOR reqData = { uWaitFlags, uTimeoutMS };482 rc = GstCntlProcessRequestAllocEx(&pRequest, VBOXSERVICECTRLREQUEST_WAIT_FOR,483 &reqData, sizeof(reqData), pHostCtx->uContextID);484 if (RT_SUCCESS(rc))485 {486 rc = GstCntlProcessPerform(uPID, pRequest);487 GstCntlProcessRequestFree(pRequest);488 }489 }490 491 return rc;492 }493 494 495 /**496 * Gets output from stdout/stderr of a specified guest process.497 *498 * @return IPRT status code.499 * @param uPID PID of process to retrieve the output from.500 * @param uCID Context ID.501 * @param uHandleId Stream ID (stdout = 0, stderr = 2) to get the output from.502 * @param cMsTimeout Timeout (in ms) to wait for output becoming503 * available.504 * @param pvBuf Pointer to a pre-allocated buffer to store the output.505 * @param cbBuf Size (in bytes) of the pre-allocated buffer.506 * @param pcbRead Pointer to number of bytes read. Optional.507 */508 int VBoxServiceControlExecGetOutput(uint32_t uPID, uint32_t uCID,509 uint32_t uHandleId, uint32_t cMsTimeout,510 void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)511 {512 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);513 AssertReturn(cbBuf, VERR_INVALID_PARAMETER);514 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);515 516 int rc = VINF_SUCCESS;517 VBOXSERVICECTRLREQUESTTYPE reqType = VBOXSERVICECTRLREQUEST_UNKNOWN; /* (gcc maybe, well, wrong.) */518 switch (uHandleId)519 {520 case OUTPUT_HANDLE_ID_STDERR:521 reqType = VBOXSERVICECTRLREQUEST_PROC_STDERR;522 break;523 524 case OUTPUT_HANDLE_ID_STDOUT:525 case OUTPUT_HANDLE_ID_STDOUT_DEPRECATED:526 reqType = VBOXSERVICECTRLREQUEST_PROC_STDOUT;527 break;528 529 default:530 rc = VERR_INVALID_PARAMETER;531 break;532 }533 534 if (RT_SUCCESS(rc))535 {536 PVBOXSERVICECTRLREQUEST pRequest;537 rc = GstCntlProcessRequestAllocEx(&pRequest, reqType, pvBuf, cbBuf, uCID);538 if (RT_SUCCESS(rc))539 {540 rc = GstCntlProcessPerform(uPID, pRequest);541 if (RT_SUCCESS(rc) && pcbRead)542 *pcbRead = pRequest->cbData;543 GstCntlProcessRequestFree(pRequest);544 }545 }546 547 return rc;548 }549 550 551 /**552 * Sets the specified guest thread to a certain list.553 *554 * @return IPRT status code.555 * @param enmList List to move thread to.556 * @param pThread Thread to set inactive.557 */558 int GstCntlListSet(VBOXSERVICECTRLTHREADLISTTYPE enmList,559 PVBOXSERVICECTRLTHREAD pThread)560 {561 AssertReturn(enmList > VBOXSERVICECTRLTHREADLIST_UNKNOWN, VERR_INVALID_PARAMETER);562 AssertPtrReturn(pThread, VERR_INVALID_POINTER);563 564 int rc = RTCritSectEnter(&g_csControlThreads);565 if (RT_SUCCESS(rc))566 {567 VBoxServiceVerbose(3, "Setting thread (PID %RU32) to list %d\n",568 pThread->uPID, enmList);569 570 PRTLISTANCHOR pAnchor = NULL;571 switch (enmList)572 {573 case VBOXSERVICECTRLTHREADLIST_STOPPED:574 pAnchor = &g_lstControlThreadsInactive;575 break;576 577 case VBOXSERVICECTRLTHREADLIST_RUNNING:578 pAnchor = &g_lstControlThreadsActive;579 break;580 581 default:582 AssertMsgFailed(("Unknown list type: %u", enmList));583 break;584 }585 586 if (!pAnchor)587 rc = VERR_INVALID_PARAMETER;588 589 if (RT_SUCCESS(rc))590 {591 if (pThread->pAnchor != NULL)592 {593 /* If thread was assigned to a list before,594 * remove the thread from the old list first. */595 /* rc = */ RTListNodeRemove(&pThread->Node);596 }597 598 /* Add thread to desired list. */599 /* rc = */ RTListAppend(pAnchor, &pThread->Node);600 pThread->pAnchor = pAnchor;601 }602 603 int rc2 = RTCritSectLeave(&g_csControlThreads);604 if (RT_SUCCESS(rc))605 rc = rc2;606 }607 608 return VINF_SUCCESS;609 }610 611 612 /**613 * Injects input to a specified running process.614 *615 * @return IPRT status code.616 * @param uPID PID of process to set the input for.617 * @param fPendingClose Flag indicating whether this is the last input block sent to the process.618 * @param pvBuf Pointer to a buffer containing the actual input data.619 * @param cbBuf Size (in bytes) of the input buffer data.620 * @param pcbWritten Pointer to number of bytes written to the process. Optional.621 */622 int VBoxServiceControlSetInput(uint32_t uPID, uint32_t uCID,623 bool fPendingClose,624 void *pvBuf, uint32_t cbBuf,625 uint32_t *pcbWritten)626 {627 /* pvBuf is optional. */628 /* cbBuf is optional. */629 /* pcbWritten is optional. */630 631 PVBOXSERVICECTRLREQUEST pRequest;632 int rc = GstCntlProcessRequestAllocEx(&pRequest,633 fPendingClose634 ? VBOXSERVICECTRLREQUEST_PROC_STDIN_EOF635 : VBOXSERVICECTRLREQUEST_PROC_STDIN,636 pvBuf, cbBuf, uCID);637 if (RT_SUCCESS(rc))638 {639 rc = GstCntlProcessPerform(uPID, pRequest);640 if (RT_SUCCESS(rc))641 {642 if (pcbWritten)643 *pcbWritten = pRequest->cbData;644 }645 646 GstCntlProcessRequestFree(pRequest);647 }648 649 return rc;650 }651 652 653 /**654 * Handles input for a started process by copying the received data into its655 * stdin pipe.656 *657 * @returns IPRT status code.658 * @param pvScratchBuf The scratch buffer.659 * @param cbScratchBuf The scratch buffer size for retrieving the input data.660 */661 static int gstcntlHandleProcInput(PVBGLR3GUESTCTRLHOSTCTX pHostCtx,662 void *pvScratchBuf, size_t cbScratchBuf)663 {664 AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);665 AssertPtrReturn(cbScratchBuf, VERR_INVALID_PARAMETER);666 AssertPtrReturn(pvScratchBuf, VERR_INVALID_POINTER);667 668 uint32_t uPID;669 uint32_t uFlags;670 uint32_t cbSize;671 672 uint32_t uStatus = INPUT_STS_UNDEFINED; /* Status sent back to the host. */673 uint32_t cbWritten = 0; /* Number of bytes written to the guest. */674 675 /*676 * Ask the host for the input data.677 */678 int rc = VbglR3GuestCtrlProcGetInput(pHostCtx, &uPID, &uFlags,679 pvScratchBuf, cbScratchBuf, &cbSize);680 if (RT_FAILURE(rc))681 {682 VBoxServiceError("[PID %RU32]: Failed to retrieve exec input command! Error: %Rrc\n",683 uPID, rc);684 }685 else if (cbSize > cbScratchBuf)686 {687 VBoxServiceError("[PID %RU32]: Too much input received! cbSize=%u, cbScratchBuf=%u\n",688 uPID, cbSize, cbScratchBuf);689 rc = VERR_INVALID_PARAMETER;690 }691 else692 {693 /*694 * Is this the last input block we need to deliver? Then let the pipe know ...695 */696 bool fPendingClose = false;697 if (uFlags & INPUT_FLAG_EOF)698 {699 fPendingClose = true;700 VBoxServiceVerbose(4, "[PID %RU32]: Got last input block of size %u ...\n",701 uPID, cbSize);702 }703 704 rc = VBoxServiceControlSetInput(uPID, pHostCtx->uContextID, fPendingClose, pvScratchBuf,705 cbSize, &cbWritten);706 VBoxServiceVerbose(4, "[PID %RU32]: Written input, CID=%u, rc=%Rrc, uFlags=0x%x, fPendingClose=%d, cbSize=%u, cbWritten=%u\n",707 uPID, pHostCtx->uContextID, rc, uFlags, fPendingClose, cbSize, cbWritten);708 if (RT_SUCCESS(rc))709 {710 uStatus = INPUT_STS_WRITTEN;711 uFlags = 0; /* No flags at the moment. */712 }713 else714 {715 if (rc == VERR_BAD_PIPE)716 uStatus = INPUT_STS_TERMINATED;717 else if (rc == VERR_BUFFER_OVERFLOW)718 uStatus = INPUT_STS_OVERFLOW;719 }720 }721 722 /*723 * If there was an error and we did not set the host status724 * yet, then do it now.725 */726 if ( RT_FAILURE(rc)727 && uStatus == INPUT_STS_UNDEFINED)728 {729 uStatus = INPUT_STS_ERROR;730 uFlags = rc;731 }732 Assert(uStatus > INPUT_STS_UNDEFINED);733 734 VBoxServiceVerbose(3, "[PID %RU32]: Input processed, CID=%u, uStatus=%u, uFlags=0x%x, cbWritten=%u\n",735 uPID, pHostCtx->uContextID, uStatus, uFlags, cbWritten);736 737 /* Note: Since the context ID is unique the request *has* to be completed here,738 * regardless whether we got data or not! Otherwise the progress object739 * on the host never will get completed! */740 rc = VbglR3GuestCtrlProcCbStatusInput(pHostCtx->uClientID, pHostCtx->uContextID, uPID,741 uStatus, uFlags, (uint32_t)cbWritten);742 743 if (RT_FAILURE(rc))744 VBoxServiceError("[PID %RU32]: Failed to report input status! Error: %Rrc\n",745 uPID, rc);746 return rc;747 }748 749 750 /**751 * Handles the guest control output command.752 *753 * @return IPRT status code.754 */755 static int gstcntlHandleProcOutput(PVBGLR3GUESTCTRLHOSTCTX pHostCtx)756 {757 AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);758 759 uint32_t uPID;760 uint32_t uHandleID;761 uint32_t uFlags;762 763 int rc = VbglR3GuestCtrlProcGetOutput(pHostCtx, &uPID, &uHandleID, &uFlags);764 if (RT_SUCCESS(rc))765 {766 uint8_t *pBuf = (uint8_t*)RTMemAlloc(_64K);767 if (pBuf)768 {769 uint32_t cbRead = 0;770 rc = VBoxServiceControlExecGetOutput(uPID, pHostCtx->uContextID, uHandleID, RT_INDEFINITE_WAIT /* Timeout */,771 pBuf, _64K /* cbSize */, &cbRead);772 VBoxServiceVerbose(3, "[PID %RU32]: Got output, rc=%Rrc, CID=%u, cbRead=%u, uHandle=%u, uFlags=%u\n",773 uPID, rc, pHostCtx->uContextID, cbRead, uHandleID, uFlags);774 775 #ifdef DEBUG776 if ( g_fControlDumpStdErr777 && uHandleID == OUTPUT_HANDLE_ID_STDERR)778 {779 char szPID[RTPATH_MAX];780 if (!RTStrPrintf(szPID, sizeof(szPID), "VBoxService_PID%u_StdOut.txt", uPID))781 rc = VERR_BUFFER_UNDERFLOW;782 if (RT_SUCCESS(rc))783 rc = gstcntlDumpToFile(szPID, pBuf, cbRead);784 }785 else if ( g_fControlDumpStdOut786 && ( uHandleID == OUTPUT_HANDLE_ID_STDOUT787 || uHandleID == OUTPUT_HANDLE_ID_STDOUT_DEPRECATED))788 {789 char szPID[RTPATH_MAX];790 if (!RTStrPrintf(szPID, sizeof(szPID), "VBoxService_PID%u_StdOut.txt", uPID))791 rc = VERR_BUFFER_UNDERFLOW;792 if (RT_SUCCESS(rc))793 rc = gstcntlDumpToFile(szPID, pBuf, cbRead);794 AssertRC(rc);795 }796 #endif797 /** Note: Don't convert/touch/modify/whatever the output data here! This might be binary798 * data which the host needs to work with -- so just pass through all data unfiltered! */799 800 /* Note: Since the context ID is unique the request *has* to be completed here,801 * regardless whether we got data or not! Otherwise the progress object802 * on the host never will get completed! */803 int rc2 = VbglR3GuestCtrlProcCbOutput(pHostCtx->uClientID, pHostCtx->uContextID, uPID, uHandleID, uFlags,804 pBuf, cbRead);805 if (RT_SUCCESS(rc))806 rc = rc2;807 else if (rc == VERR_NOT_FOUND) /* It's not critical if guest process (PID) is not found. */808 rc = VINF_SUCCESS;809 810 RTMemFree(pBuf);811 }812 else813 rc = VERR_NO_MEMORY;814 }815 816 if (RT_FAILURE(rc))817 VBoxServiceError("[PID %RU32]: Error handling output command! Error: %Rrc\n",818 uPID, rc);819 272 return rc; 820 273 } … … 840 293 pHostCtx->uClientID, pHostCtx->uProtocol); 841 294 842 rc = GstCntlSessionOpen(&ssInfo, NULL /* Node */); 295 rc = GstCntlSessionThreadOpen(&g_lstControlSessionThreads, 296 &ssInfo, NULL /* Session */); 843 297 } 844 298 … … 869 323 rc = VERR_NOT_FOUND; 870 324 871 PVBOXSERVICECTRLSESSION pSession;872 RTListForEach(&g_lstControlSession s, pSession, VBOXSERVICECTRLSESSION, Node)325 PVBOXSERVICECTRLSESSIONTHREAD pSession; 326 RTListForEach(&g_lstControlSessionThreads, pSession, VBOXSERVICECTRLSESSIONTHREAD, Node) 873 327 { 874 328 if (pSession->StartupInfo.uSessionID == uSessionID) 875 329 { 876 rc = GstCntlSession Close(pSession, uFlags);330 rc = GstCntlSessionThreadClose(pSession, uFlags); 877 331 break; 878 332 } … … 923 377 924 378 /** 925 * Reaps all inactive guest process threads.926 *927 * @return IPRT status code.928 */929 static int gstcntlReapThreads(void)930 {931 int rc = RTCritSectEnter(&g_csControlThreads);932 if (RT_SUCCESS(rc))933 {934 PVBOXSERVICECTRLTHREAD pThread =935 RTListGetFirst(&g_lstControlThreadsInactive, VBOXSERVICECTRLTHREAD, Node);936 while (pThread)937 {938 PVBOXSERVICECTRLTHREAD pNext = RTListNodeGetNext(&pThread->Node, VBOXSERVICECTRLTHREAD, Node);939 bool fLast = RTListNodeIsLast(&g_lstControlThreadsInactive, &pThread->Node);940 int rc2 = GstCntlProcessWait(pThread, 30 * 1000 /* 30 seconds max. */,941 NULL /* rc */);942 if (RT_SUCCESS(rc2))943 {944 RTListNodeRemove(&pThread->Node);945 946 rc2 = GstCntlProcessFree(pThread);947 if (RT_FAILURE(rc2))948 {949 VBoxServiceError("Freeing guest process thread failed with rc=%Rrc\n", rc2);950 if (RT_SUCCESS(rc)) /* Keep original failure. */951 rc = rc2;952 }953 }954 else955 VBoxServiceError("Waiting on guest process thread failed with rc=%Rrc\n", rc2);956 /* Keep going. */957 958 if (fLast)959 break;960 961 pThread = pNext;962 }963 964 int rc2 = RTCritSectLeave(&g_csControlThreads);965 if (RT_SUCCESS(rc))966 rc = rc2;967 }968 969 VBoxServiceVerbose(4, "Reaping threads returned with rc=%Rrc\n", rc);970 return rc;971 }972 973 974 static int vboxServiceControlProcessClose()975 {976 /** Note: This will be a guest tsession task later. */977 978 /* Signal all threads in the active list that we want to shutdown. */979 PVBOXSERVICECTRLTHREAD pThread;980 RTListForEach(&g_lstControlThreadsActive, pThread, VBOXSERVICECTRLTHREAD, Node)981 GstCntlProcessStop(pThread);982 983 /* Wait for all active threads to shutdown and destroy the active thread list. */984 pThread = RTListGetFirst(&g_lstControlThreadsActive, VBOXSERVICECTRLTHREAD, Node);985 while (pThread)986 {987 PVBOXSERVICECTRLTHREAD pNext = RTListNodeGetNext(&pThread->Node, VBOXSERVICECTRLTHREAD, Node);988 bool fLast = RTListNodeIsLast(&g_lstControlThreadsActive, &pThread->Node);989 990 int rc2 = GstCntlProcessWait(pThread,991 30 * 1000 /* Wait 30 seconds max. */,992 NULL /* rc */);993 if (RT_FAILURE(rc2))994 {995 VBoxServiceError("Guest process thread failed to stop; rc=%Rrc\n", rc2);996 /* Keep going. */997 }998 999 if (fLast)1000 break;1001 1002 pThread = pNext;1003 }1004 1005 int rc = gstcntlReapThreads();1006 if (RT_FAILURE(rc))1007 VBoxServiceError("Reaping inactive threads failed with rc=%Rrc\n", rc);1008 1009 AssertMsg(RTListIsEmpty(&g_lstControlThreadsActive),1010 ("Guest process active thread list still contains entries when it should not\n"));1011 AssertMsg(RTListIsEmpty(&g_lstControlThreadsInactive),1012 ("Guest process inactive thread list still contains entries when it should not\n"));1013 1014 return rc;1015 }1016 1017 1018 static int vboxServiceControlProcessCloseAll(void)1019 {1020 return vboxServiceControlProcessClose();1021 }1022 1023 1024 /**1025 379 * Destroys all guest process threads which are still active. 1026 380 */ … … 1029 383 VBoxServiceVerbose(2, "Shutting down ...\n"); 1030 384 1031 int rc2 = vboxServiceControlProcessCloseAll(); 1032 AssertRC(rc2); 1033 1034 /* Destroy critical section. */ 1035 RTCritSectDelete(&g_csControlThreads); 385 /* int GstCntlSessionDestroy(PVBOXSERVICECTRLSESSION pSession) */ 1036 386 1037 387 VBoxServiceVerbose(2, "Shutting down complete\n"); … … 1056 406 g_hControlEvent = NIL_RTSEMEVENTMULTI; 1057 407 } 1058 }1059 1060 1061 /**1062 * Determines whether starting a new guest process according to the1063 * maximum number of concurrent guest processes defined is allowed or not.1064 *1065 * @return IPRT status code.1066 * @param pbAllowed True if starting (another) guest process1067 * is allowed, false if not.1068 */1069 static int gstcntlStartAllowed(bool *pbAllowed)1070 {1071 AssertPtrReturn(pbAllowed, VERR_INVALID_POINTER);1072 1073 int rc = RTCritSectEnter(&g_csControlThreads);1074 if (RT_SUCCESS(rc))1075 {1076 /*1077 * Check if we're respecting our memory policy by checking1078 * how many guest processes are started and served already.1079 */1080 bool fLimitReached = false;1081 if (g_uControlProcsMaxKept) /* If we allow unlimited processes (=0), take a shortcut. */1082 {1083 uint32_t uProcsRunning = 0;1084 PVBOXSERVICECTRLTHREAD pThread;1085 RTListForEach(&g_lstControlThreadsActive, pThread, VBOXSERVICECTRLTHREAD, Node)1086 uProcsRunning++;1087 1088 VBoxServiceVerbose(3, "Maximum served guest processes set to %u, running=%u\n",1089 g_uControlProcsMaxKept, uProcsRunning);1090 1091 int32_t iProcsLeft = (g_uControlProcsMaxKept - uProcsRunning - 1);1092 if (iProcsLeft < 0)1093 {1094 VBoxServiceVerbose(3, "Maximum running guest processes reached (%u)\n",1095 g_uControlProcsMaxKept);1096 fLimitReached = true;1097 }1098 }1099 1100 *pbAllowed = !fLimitReached;1101 1102 int rc2 = RTCritSectLeave(&g_csControlThreads);1103 if (RT_SUCCESS(rc))1104 rc = rc2;1105 }1106 1107 return rc;1108 }1109 1110 1111 /**1112 * Finds a (formerly) started process given by its PID and locks it. Must be unlocked1113 * by the caller with VBoxServiceControlThreadUnlock().1114 *1115 * @return PVBOXSERVICECTRLTHREAD Process structure if found, otherwise NULL.1116 * @param uPID PID to search for.1117 */1118 PVBOXSERVICECTRLTHREAD GstCntlLockThread(uint32_t uPID)1119 {1120 PVBOXSERVICECTRLTHREAD pThread = NULL;1121 int rc = RTCritSectEnter(&g_csControlThreads);1122 if (RT_SUCCESS(rc))1123 {1124 PVBOXSERVICECTRLTHREAD pThreadCur;1125 RTListForEach(&g_lstControlThreadsActive, pThreadCur, VBOXSERVICECTRLTHREAD, Node)1126 {1127 if (pThreadCur->uPID == uPID)1128 {1129 rc = RTCritSectEnter(&pThreadCur->CritSect);1130 if (RT_SUCCESS(rc))1131 pThread = pThreadCur;1132 break;1133 }1134 }1135 1136 int rc2 = RTCritSectLeave(&g_csControlThreads);1137 if (RT_SUCCESS(rc))1138 rc = rc2;1139 }1140 1141 return pThread;1142 }1143 1144 1145 /**1146 * Unlocks a previously locked guest process thread.1147 *1148 * @param pThread Thread to unlock.1149 */1150 void GstCntlUnlockThread(const PVBOXSERVICECTRLTHREAD pThread)1151 {1152 AssertPtr(pThread);1153 1154 int rc = RTCritSectLeave(&pThread->CritSect);1155 AssertRC(rc);1156 }1157 1158 1159 /**1160 * Assigns a valid PID to a guest control thread and also checks if there already was1161 * another (stale) guest process which was using that PID before and destroys it.1162 *1163 * @return IPRT status code.1164 * @param pThread Thread to assign PID to.1165 * @param uPID PID to assign to the specified guest control execution thread.1166 */1167 int GstCntlAssignPID(PVBOXSERVICECTRLTHREAD pThread, uint32_t uPID)1168 {1169 AssertPtrReturn(pThread, VERR_INVALID_POINTER);1170 AssertReturn(uPID, VERR_INVALID_PARAMETER);1171 1172 int rc = RTCritSectEnter(&g_csControlThreads);1173 if (RT_SUCCESS(rc))1174 {1175 /* Search old threads using the desired PID and shut them down completely -- it's1176 * not used anymore. */1177 PVBOXSERVICECTRLTHREAD pThreadCur;1178 bool fTryAgain = false;1179 do1180 {1181 RTListForEach(&g_lstControlThreadsActive, pThreadCur, VBOXSERVICECTRLTHREAD, Node)1182 {1183 if (pThreadCur->uPID == uPID)1184 {1185 Assert(pThreadCur != pThread); /* can't happen */1186 uint32_t uTriedPID = uPID;1187 uPID += 391939;1188 VBoxServiceVerbose(2, "PID %RU32 was used before, trying again with %u ...\n",1189 uTriedPID, uPID);1190 fTryAgain = true;1191 break;1192 }1193 }1194 } while (fTryAgain);1195 1196 /* Assign PID to current thread. */1197 pThread->uPID = uPID;1198 1199 rc = RTCritSectLeave(&g_csControlThreads);1200 AssertRC(rc);1201 }1202 1203 return rc;1204 408 } 1205 409 -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.h
r44935 r44963 123 123 uint32_t uTimeoutMS; 124 124 } VBOXSERVICECTRLREQDATA_WAIT_FOR, *PVBOXSERVICECTRLREQDATA_WAIT_FOR; 125 126 /** 127 * Structure for one (opened) guest file. 128 */ 129 typedef struct VBOXSERVICECTRLFILE 130 { 131 /** Pointer to list archor of following 132 * list node. 133 * @todo Would be nice to have a RTListGetAnchor(). */ 134 PRTLISTANCHOR pAnchor; 135 /** Node to global guest control file list. */ 136 /** @todo Use a map later? */ 137 RTLISTNODE Node; 138 /** The file name. */ 139 char szName[RTPATH_MAX]; 140 /** The file handle on the guest. */ 141 RTFILE hFile; 142 /** File handle to identify this file. */ 143 uint32_t uHandle; 144 /** Context ID. */ 145 uint32_t uContextID; 146 } VBOXSERVICECTRLFILE; 147 /** Pointer to thread data. */ 148 typedef VBOXSERVICECTRLFILE *PVBOXSERVICECTRLFILE; 149 150 typedef struct VBOXSERVICECTRLSESSIONSTARTUPINFO 151 { 152 /** The session's protocol version to use. */ 153 uint32_t uProtocol; 154 /** The session's ID. */ 155 uint32_t uSessionID; 156 /** User name (account) to start the guest session under. */ 157 char szUser[GUESTPROCESS_MAX_USER_LEN]; 158 /** Password of specified user name (account). */ 159 char szPassword[GUESTPROCESS_MAX_PASSWORD_LEN]; 160 /** Domain of the user account. */ 161 char szDomain[GUESTPROCESS_MAX_DOMAIN_LEN]; 162 /** Session creation flags. 163 * @sa VBOXSERVICECTRLSESSIONSTARTUPFLAG_* flags. */ 164 uint32_t uFlags; 165 } VBOXSERVICECTRLSESSIONSTARTUPINFO; 166 /** Pointer to thread data. */ 167 typedef VBOXSERVICECTRLSESSIONSTARTUPINFO *PVBOXSERVICECTRLSESSIONSTARTUPINFO; 168 169 /** 170 * Structure for a guest session thread to 171 * observe the forked session instance. 172 */ 173 typedef struct VBOXSERVICECTRLSESSIONTHREAD 174 { 175 /** Node to global guest control session list. */ 176 /** @todo Use a map later? */ 177 RTLISTNODE Node; 178 /** The sessions's startup info. */ 179 VBOXSERVICECTRLSESSIONSTARTUPINFO 180 StartupInfo; 181 /** The worker thread. */ 182 RTTHREAD Thread; 183 /** Critical section for thread-safe use. */ 184 RTCRITSECT CritSect; 185 /** Process handle for forked child. */ 186 RTPROCESS hProcess; 187 /** Shutdown indicator; will be set when the thread 188 * needs (or is asked) to shutdown. */ 189 bool volatile fShutdown; 190 /** Indicator set by the service thread exiting. */ 191 bool volatile fStopped; 192 /** Whether the thread was started or not. */ 193 bool fStarted; 194 #if 0 /* Pipe IPC not used yet. */ 195 /** Pollset containing all the pipes. */ 196 RTPOLLSET hPollSet; 197 RTPIPE hStdInW; 198 RTPIPE hStdOutR; 199 RTPIPE hStdErrR; 200 struct StdPipe 201 { 202 RTHANDLE hChild; 203 PRTHANDLE phChild; 204 } StdIn, 205 StdOut, 206 StdErr; 207 /** The notification pipe associated with this guest session. 208 * This is NIL_RTPIPE for output pipes. */ 209 RTPIPE hNotificationPipeW; 210 /** The other end of hNotificationPipeW. */ 211 RTPIPE hNotificationPipeR; 212 #endif 213 } VBOXSERVICECTRLSESSIONTHREAD; 214 /** Pointer to thread data. */ 215 typedef VBOXSERVICECTRLSESSIONTHREAD *PVBOXSERVICECTRLSESSIONTHREAD; 216 217 /** @todo Documentation needed. */ 218 #define VBOXSERVICECTRLSESSION_FLAG_FORK RT_BIT(0) 219 #define VBOXSERVICECTRLSESSION_FLAG_DUMPSTDOUT RT_BIT(1) 220 #define VBOXSERVICECTRLSESSION_FLAG_DUMPSTDERR RT_BIT(2) 221 222 /** 223 * Strucutre for maintaining a guest session. This also 224 * contains all started threads (e.g. for guest processes). 225 * 226 * This structure can act in two different ways: 227 * - For legacy guest control handling (protocol version < 2) 228 * this acts as a per-guest process structure containing all 229 * the information needed to get a guest process up and running. 230 * - For newer guest control protocols (>= 2) this structure is 231 * part of the forked session child, maintaining all guest 232 * control objects under it. 233 */ 234 typedef struct VBOXSERVICECTRLSESSION 235 { 236 VBOXSERVICECTRLSESSIONSTARTUPINFO 237 StartupInfo; 238 /** List of active guest control threads (VBOXSERVICECTRLTHREAD). */ 239 RTLISTANCHOR lstControlThreadsActive; 240 /** List of inactive guest control threads (VBOXSERVICECTRLTHREAD). */ 241 /** @todo Still needed? */ 242 RTLISTANCHOR lstControlThreadsInactive; 243 /** List of guest control files (VBOXSERVICECTRLFILE). */ 244 RTLISTANCHOR lstFiles; 245 /** Critical section for protecting the guest process 246 * threading list. */ 247 RTCRITSECT csControlThreads; 248 /** Session flags. */ 249 uint32_t uFlags; 250 /** How many processes do we allow keeping around at a time? */ 251 uint32_t uProcsMaxKept; 252 } VBOXSERVICECTRLSESSION; 253 /** Pointer to guest session. */ 254 typedef VBOXSERVICECTRLSESSION *PVBOXSERVICECTRLSESSION; 125 255 126 256 /** … … 175 305 /** The worker thread. */ 176 306 RTTHREAD Thread; 307 /** The session this guest process 308 * is bound to. */ 309 PVBOXSERVICECTRLSESSION pSession; 177 310 /** Shutdown indicator; will be set when the thread 178 311 * needs (or is asked) to shutdown. */ … … 219 352 typedef VBOXSERVICECTRLTHREAD *PVBOXSERVICECTRLTHREAD; 220 353 221 /**222 * Structure for one (opened) guest file.223 */224 typedef struct VBOXSERVICECTRLFILE225 {226 /** Pointer to list archor of following227 * list node.228 * @todo Would be nice to have a RTListGetAnchor(). */229 PRTLISTANCHOR pAnchor;230 /** Node to global guest control file list. */231 /** @todo Use a map later? */232 RTLISTNODE Node;233 /** The file name. */234 char szName[RTPATH_MAX];235 /** The file handle on the guest. */236 RTFILE hFile;237 /** File handle to identify this file. */238 uint32_t uHandle;239 /** Context ID. */240 uint32_t uContextID;241 } VBOXSERVICECTRLFILE;242 /** Pointer to thread data. */243 typedef VBOXSERVICECTRLFILE *PVBOXSERVICECTRLFILE;244 245 typedef struct VBOXSERVICECTRLSESSIONSTARTUPINFO246 {247 /** The session's protocol version to use. */248 uint32_t uProtocol;249 /** The session's ID. */250 uint32_t uSessionID;251 /** User name (account) to start the guest session under. */252 char szUser[GUESTPROCESS_MAX_USER_LEN];253 /** Password of specified user name (account). */254 char szPassword[GUESTPROCESS_MAX_PASSWORD_LEN];255 /** Domain of the user account. */256 char szDomain[GUESTPROCESS_MAX_DOMAIN_LEN];257 /** Session creation flags.258 * @sa VBOXSERVICECTRLSESSIONSTARTUPFLAG_* flags. */259 uint32_t uFlags;260 } VBOXSERVICECTRLSESSIONSTARTUPINFO;261 /** Pointer to thread data. */262 typedef VBOXSERVICECTRLSESSIONSTARTUPINFO *PVBOXSERVICECTRLSESSIONSTARTUPINFO;263 264 /**265 * Structure for a (forked) guest session.266 */267 typedef struct VBOXSERVICECTRLSESSION268 {269 /** Node to global guest control session list. */270 /** @todo Use a map later? */271 RTLISTNODE Node;272 /** The sessions's startup info. */273 VBOXSERVICECTRLSESSIONSTARTUPINFO274 StartupInfo;275 /** The worker thread. */276 RTTHREAD Thread;277 /** Critical section for thread-safe use. */278 RTCRITSECT CritSect;279 /** Process handle for forked child. */280 RTPROCESS hProcess;281 /** Shutdown indicator; will be set when the thread282 * needs (or is asked) to shutdown. */283 bool volatile fShutdown;284 /** Indicator set by the service thread exiting. */285 bool volatile fStopped;286 /** Whether the thread was started or not. */287 bool fStarted;288 #if 0 /* Pipe IPC not used yet. */289 /** Pollset containing all the pipes. */290 RTPOLLSET hPollSet;291 RTPIPE hStdInW;292 RTPIPE hStdOutR;293 RTPIPE hStdErrR;294 struct StdPipe295 {296 RTHANDLE hChild;297 PRTHANDLE phChild;298 } StdIn,299 StdOut,300 StdErr;301 /** The notification pipe associated with this guest session.302 * This is NIL_RTPIPE for output pipes. */303 RTPIPE hNotificationPipeW;304 /** The other end of hNotificationPipeW. */305 RTPIPE hNotificationPipeR;306 #endif307 } VBOXSERVICECTRLSESSION;308 /** Pointer to thread data. */309 typedef VBOXSERVICECTRLSESSION *PVBOXSERVICECTRLSESSION;310 311 354 RT_C_DECLS_BEGIN 312 355 … … 321 364 */ 322 365 323 /* Guest session handling. */324 extern int GstCntlSession Open(const PVBOXSERVICECTRLSESSIONSTARTUPINFO pSessionStartupInfo, PRTLISTNODE pNode);325 extern int GstCntlSession Close(PVBOXSERVICECTRLSESSIONpSession, uint32_t uFlags);326 extern int GstCntlSessionT erminate(PVBOXSERVICECTRLSESSIONpSession);366 /* Guest session thread handling. */ 367 extern int GstCntlSessionThreadOpen(PRTLISTANCHOR pList, const PVBOXSERVICECTRLSESSIONSTARTUPINFO pSessionStartupInfo, PVBOXSERVICECTRLSESSIONTHREAD *ppSessionThread); 368 extern int GstCntlSessionThreadClose(PVBOXSERVICECTRLSESSIONTHREAD pSession, uint32_t uFlags); 369 extern int GstCntlSessionThreadTerminate(PVBOXSERVICECTRLSESSIONTHREAD pSession); 327 370 extern RTEXITCODE VBoxServiceControlSessionForkInit(int argc, char **argv); 328 371 372 /* asdf */ 373 extern PVBOXSERVICECTRLTHREAD GstCntlSessionAcquireProcess(PVBOXSERVICECTRLSESSION pSession, uint32_t uPID); 374 extern int GstCntlSessionCloseAll(PVBOXSERVICECTRLSESSION pSession); 375 extern int GstCntlSessionDestroy(PVBOXSERVICECTRLSESSION pSession); 376 extern int GstCntlSessionHandler(PVBOXSERVICECTRLSESSION pSession, uint32_t uMsg, PVBGLR3GUESTCTRLHOSTCTX pHostCtx, void *pvScratchBuf, size_t cbScratchBuf, volatile bool *pfShutdown); 377 extern int GstCntlSessionListSet(PVBOXSERVICECTRLSESSION pSession, VBOXSERVICECTRLTHREADLISTTYPE enmList, PVBOXSERVICECTRLTHREAD pThread); 378 extern int GstCntlSessionProcessStartAllowed(const PVBOXSERVICECTRLSESSION pSession, bool *pbAllowed); 379 extern int GstCntlSessionReapThreads(PVBOXSERVICECTRLSESSION pSession); 380 329 381 /* Guest control main thread functions. */ 330 extern int GstCntlAssignPID(PVBOXSERVICECTRLTHREAD pThread, uint32_t uPID);331 382 extern int GstCntlListSet(VBOXSERVICECTRLTHREADLISTTYPE enmList, PVBOXSERVICECTRLTHREAD pThread); 332 extern PVBOXSERVICECTRLTHREAD GstCntlLockThread(uint32_t uPID);333 extern void GstCntlUnlockThread(const PVBOXSERVICECTRLTHREAD pThread);334 383 extern int GstCntlSetInactive(PVBOXSERVICECTRLTHREAD pThread); 335 384 /* Per-thread guest process functions. */ 336 extern int Gst cntlProcessSetupPipe(const char *pszHowTo, int fd, PRTHANDLE ph, PRTHANDLE *pph, PRTPIPE phPipe);385 extern int GstCntlProcessPerform(PVBOXSERVICECTRLTHREAD pProcess, PVBOXSERVICECTRLREQUEST pRequest); 337 386 extern int GstCntlProcessStart(uint32_t uContext, PVBOXSERVICECTRLPROCESS pProcess); 338 extern int GstCntlProcessPerform(uint32_t uPID, PVBOXSERVICECTRLREQUEST pRequest);339 387 extern int GstCntlProcessStop(const PVBOXSERVICECTRLTHREAD pThread); 388 extern void GstCntlProcessRelease(const PVBOXSERVICECTRLTHREAD pThread); 340 389 extern int GstCntlProcessWait(const PVBOXSERVICECTRLTHREAD pThread, RTMSINTERVAL msTimeout, int *prc); 341 390 extern int GstCntlProcessFree(PVBOXSERVICECTRLTHREAD pThread); 342 /* Request handling. */391 /* Process request handling. */ 343 392 extern int GstCntlProcessRequestAlloc(PVBOXSERVICECTRLREQUEST *ppReq, VBOXSERVICECTRLREQUESTTYPE enmType); 344 393 extern int GstCntlProcessRequestAllocEx(PVBOXSERVICECTRLREQUEST *ppReq, VBOXSERVICECTRLREQUESTTYPE enmType, void *pvData, size_t cbData, uint32_t uCID); 345 394 extern void GstCntlProcessRequestFree(PVBOXSERVICECTRLREQUEST pReq); 346 /****************************************************************************** 347 * Guest file command handling. * 348 *****************************************************************************/ 395 /* Per-session functions. */ 349 396 extern int gstcntlHandleFileOpen(uint32_t idClient, uint32_t cParms); 350 397 extern int gstcntlHandleFileClose(uint32_t idClient, uint32_t cParms); … … 355 402 extern int gstcntlHandleFileSeek(uint32_t idClient, uint32_t cParms); 356 403 extern int gstcntlHandleFileTell(uint32_t idClient, uint32_t cParms); 404 extern int GstCntlSessionHandleProcExec(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLHOSTCTX pHostCtx); 405 extern int GstCntlSessionHandleProcInput(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLHOSTCTX pHostCtx, void *pvScratchBuf, size_t cbScratchBuf); 406 extern int GstCntlSessionHandleProcOutput(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLHOSTCTX pHostCtx); 407 extern int GstCntlSessionHandleProcTerminate(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLHOSTCTX pHostCtx); 408 extern int GstCntlSessionHandleProcWaitFor(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLHOSTCTX pHostCtx); 357 409 358 410 RT_C_DECLS_END -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlSession.cpp
r44935 r44963 40 40 using namespace guestControl; 41 41 42 /** List of guest control sessions (VBOXSERVICECTRLSESSION). */ 43 extern RTLISTANCHOR g_lstControlSessions; 42 /******************************************************************************* 43 * Externals * 44 *******************************************************************************/ 45 extern RTLISTANCHOR g_lstControlSessionThreads; 46 extern VBOXSERVICECTRLSESSION g_Session; 47 44 48 extern int VBoxServiceLogCreate(const char *pszLogFile); 45 49 extern void VBoxServiceLogDestroy(void); … … 49 53 *******************************************************************************/ 50 54 static int gstcntlSessionFileDestroy(PVBOXSERVICECTRLFILE pFile); 51 static int gstcntlSessionForkShutdown(uint32_t uClientId, uint32_t cParms); 52 static PVBOXSERVICECTRLFILE gstcntlSessionGetFile(uint32_t uHandle); 53 static int gstcntlSessionHandleFileOpen(uint32_t uClientId, uint32_t cParms); 54 static int gstcntlSessionHandleFileClose(uint32_t uClientId, uint32_t cParms); 55 static int gstcntlSessionHandleFileRead(uint32_t uClientId, uint32_t cParms); 56 static int gstcntlSessionHandleFileWrite(uint32_t uClientId, uint32_t cParms, void *pvScratchBuf, size_t cbScratchBuf); 57 static int gstcntlSessionHandleFileSeek(uint32_t uClientId, uint32_t cParms); 58 static int gstcntlSessionHandleFileTell(uint32_t uClientId, uint32_t cParms); 55 static int gstcntlSessionForkShutdown(PVBOXSERVICECTRLSESSION pSession); 56 static PVBOXSERVICECTRLFILE gstcntlSessionGetFile(const PVBOXSERVICECTRLSESSION pSession, uint32_t uHandle); 57 static int gstcntlSessionGetOutput(const PVBOXSERVICECTRLSESSION pSession, uint32_t uPID, uint32_t uCID, uint32_t uHandleId, uint32_t cMsTimeout, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead); 58 static int gstcntlSessionHandleFileOpen(PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLHOSTCTX pHostCtx); 59 static int gstcntlSessionHandleFileClose(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLHOSTCTX pHostCtx); 60 static int gstcntlSessionHandleFileRead(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLHOSTCTX pHostCtx); 61 static int gstcntlSessionHandleFileWrite(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLHOSTCTX pHostCtx, void *pvScratchBuf, size_t cbScratchBuf); 62 static int gstcntlSessionHandleFileSeek(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLHOSTCTX pHostCtx); 63 static int gstcntlSessionHandleFileTell(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLHOSTCTX pHostCtx); 64 static int gstcntlSessionSetInput(const PVBOXSERVICECTRLSESSION pSession, uint32_t uPID, uint32_t uCID, bool fPendingClose, void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten); 59 65 static DECLCALLBACK(int) gstcntlSessionThread(RTTHREAD ThreadSelf, void *pvUser); 60 61 /** The session ID of the forked session process. */62 static uint32_t g_uSessionID = UINT32_MAX;63 /** The session HGCM protocol of the forked session process. */64 static uint32_t g_uSessionProto = 1; /* Use the legacy protocol by default (< VBox 4.3). */65 /** List of guest control files (VBOXSERVICECTRLFILE). */66 static RTLISTANCHOR g_lstSessionFiles;67 66 68 67 /** Generic option indices for session fork arguments. */ … … 93 92 94 93 95 static PVBOXSERVICECTRLFILE gstcntlSessionGetFile(uint32_t uHandle) 96 { 94 static PVBOXSERVICECTRLFILE gstcntlSessionGetFile(const PVBOXSERVICECTRLSESSION pSession, 95 uint32_t uHandle) 96 { 97 AssertPtrReturn(pSession, NULL); 98 97 99 PVBOXSERVICECTRLFILE pFileCur = NULL; 98 100 /** @todo Use a map later! */ 99 RTListForEach(& g_lstSessionFiles, pFileCur, VBOXSERVICECTRLFILE, Node)101 RTListForEach(&pSession->lstFiles, pFileCur, VBOXSERVICECTRLFILE, Node) 100 102 { 101 103 if (pFileCur->uHandle == uHandle) … … 107 109 108 110 109 static int gstcntlSessionHandleFileOpen(uint32_t uClientId, uint32_t cParms) 110 { 111 #ifdef DEBUG 112 static int gstcntlSessionDumpToFile(const char *pszFileName, void *pvBuf, size_t cbBuf) 113 { 114 AssertPtrReturn(pszFileName, VERR_INVALID_POINTER); 115 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); 116 117 if (!cbBuf) 118 return VINF_SUCCESS; 119 120 char szFile[RTPATH_MAX]; 121 122 int rc = RTPathTemp(szFile, sizeof(szFile)); 123 if (RT_SUCCESS(rc)) 124 rc = RTPathAppend(szFile, sizeof(szFile), pszFileName); 125 126 if (RT_SUCCESS(rc)) 127 { 128 VBoxServiceVerbose(4, "Dumping %ld bytes to \"%s\"\n", cbBuf, szFile); 129 130 RTFILE fh; 131 rc = RTFileOpen(&fh, szFile, RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE); 132 if (RT_SUCCESS(rc)) 133 { 134 rc = RTFileWrite(fh, pvBuf, cbBuf, NULL /* pcbWritten */); 135 RTFileClose(fh); 136 } 137 } 138 139 return rc; 140 } 141 #endif 142 143 144 static int gstcntlSessionHandleFileOpen(PVBOXSERVICECTRLSESSION pSession, 145 PVBGLR3GUESTCTRLHOSTCTX pHostCtx) 146 { 147 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 148 AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER); 149 111 150 char szFile[RTPATH_MAX]; 112 151 char szOpenMode[64]; … … 116 155 117 156 uint32_t uHandle = 0; 118 VBGLR3GUESTCTRLHOSTCTX ctx = { uClientId, cParms }; 119 int rc = VbglR3GuestCtrlFileGetOpen(&ctx, 157 int rc = VbglR3GuestCtrlFileGetOpen(pHostCtx, 120 158 /* File to open. */ 121 159 szFile, sizeof(szFile), … … 156 194 if (RT_SUCCESS(rc)) 157 195 { 158 uHandle = VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT( ctx.uContextID);196 uHandle = VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pHostCtx->uContextID); 159 197 pFile->uHandle = uHandle; 160 /* rc = */ RTListAppend(& g_lstSessionFiles, &pFile->Node);198 /* rc = */ RTListAppend(&pSession->lstFiles, &pFile->Node); 161 199 162 200 VBoxServiceVerbose(3, "[File %s]: Opened (ID=%RU32)\n", … … 172 210 /* Report back in any case. */ 173 211 CALLBACKPAYLOAD_FILE_NOTFIY_OPEN cplOpen = { rc, uHandle }; 174 int rc2 = VbglR3GuestCtrlFileNotify( uClientId, ctx.uContextID, GUEST_FILE_NOTIFYTYPE_OPEN,175 &cplOpen, sizeof(cplOpen));212 int rc2 = VbglR3GuestCtrlFileNotify(pHostCtx->uClientID, pHostCtx->uContextID, 213 GUEST_FILE_NOTIFYTYPE_OPEN, &cplOpen, sizeof(cplOpen)); 176 214 if (RT_FAILURE(rc2)) 177 215 VBoxServiceError("[File %s]: Failed to report file open status, rc=%Rrc\n", … … 185 223 186 224 187 static int gstcntlSessionHandleFileClose(uint32_t uClientId, uint32_t cParms) 188 { 225 static int gstcntlSessionHandleFileClose(const PVBOXSERVICECTRLSESSION pSession, 226 PVBGLR3GUESTCTRLHOSTCTX pHostCtx) 227 { 228 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 229 AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER); 230 189 231 uint32_t uHandle; 190 232 191 VBGLR3GUESTCTRLHOSTCTX ctx = { uClientId, cParms }; 192 int rc = VbglR3GuestCtrlFileGetClose(&ctx, &uHandle /* File handle to close */); 193 if (RT_SUCCESS(rc)) 194 { 195 PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(uHandle); 233 int rc = VbglR3GuestCtrlFileGetClose(pHostCtx, &uHandle /* File handle to close */); 234 if (RT_SUCCESS(rc)) 235 { 236 PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(pSession, uHandle); 196 237 if (pFile) 197 238 { … … 203 244 /* Report back in any case. */ 204 245 CALLBACKPAYLOAD_FILE_NOTFIY_CLOSE cplClose = { rc }; 205 int rc2 = VbglR3GuestCtrlFileNotify( uClientId, ctx.uContextID, GUEST_FILE_NOTIFYTYPE_CLOSE,206 &cplClose, sizeof(cplClose));246 int rc2 = VbglR3GuestCtrlFileNotify(pHostCtx->uClientID, pHostCtx->uContextID, 247 GUEST_FILE_NOTIFYTYPE_CLOSE, &cplClose, sizeof(cplClose)); 207 248 if (RT_FAILURE(rc2)) 208 249 VBoxServiceError("Failed to report file close status, rc=%Rrc\n", rc2); … … 214 255 215 256 216 static int gstcntlSessionHandleFileRead(uint32_t uClientId, uint32_t cParms, 257 static int gstcntlSessionHandleFileRead(const PVBOXSERVICECTRLSESSION pSession, 258 PVBGLR3GUESTCTRLHOSTCTX pHostCtx, 217 259 void *pvScratchBuf, size_t cbScratchBuf) 218 260 { 261 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 262 AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER); 263 219 264 uint32_t uHandle; 220 265 uint32_t cbToRead; 221 266 222 VBGLR3GUESTCTRLHOSTCTX ctx = { uClientId, cParms }; 223 int rc = VbglR3GuestCtrlFileGetRead(&ctx, &uHandle, &cbToRead); 267 int rc = VbglR3GuestCtrlFileGetRead(pHostCtx, &uHandle, &cbToRead); 224 268 if (RT_SUCCESS(rc)) 225 269 { … … 227 271 size_t cbRead = 0; 228 272 229 PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile( uHandle);273 PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(pSession, uHandle); 230 274 if (pFile) 231 275 { … … 250 294 /* Report back in any case. */ 251 295 CALLBACKPAYLOAD_FILE_NOTFIY_READ cplRead = { rc, (uint32_t)cbRead, pvDataRead }; 252 int rc2 = VbglR3GuestCtrlFileNotify( uClientId, ctx.uContextID, GUEST_FILE_NOTIFYTYPE_READ,253 &cplRead, sizeof(cplRead));296 int rc2 = VbglR3GuestCtrlFileNotify(pHostCtx->uClientID, pHostCtx->uContextID, 297 GUEST_FILE_NOTIFYTYPE_READ, &cplRead, sizeof(cplRead)); 254 298 if ( cbToRead > cbScratchBuf 255 299 && pvDataRead) … … 265 309 266 310 267 static int gstcntlSessionHandleFileReadAt(uint32_t uClientId, uint32_t cParms, 311 static int gstcntlSessionHandleFileReadAt(const PVBOXSERVICECTRLSESSION pSession, 312 PVBGLR3GUESTCTRLHOSTCTX pHostCtx, 268 313 void *pvScratchBuf, size_t cbScratchBuf) 269 314 { 315 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 316 AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER); 317 270 318 uint32_t uHandle; 271 319 uint32_t cbToRead; int64_t iOffset; 272 320 273 VBGLR3GUESTCTRLHOSTCTX ctx = { uClientId, cParms };274 int rc = VbglR3GuestCtrlFileGetReadAt(&ctx,&uHandle, &cbToRead, (uint64_t*)&iOffset);321 int rc = VbglR3GuestCtrlFileGetReadAt(pHostCtx, 322 &uHandle, &cbToRead, (uint64_t*)&iOffset); 275 323 if (RT_SUCCESS(rc)) 276 324 { … … 278 326 size_t cbRead = 0; 279 327 280 PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile( uHandle);328 PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(pSession, uHandle); 281 329 if (pFile) 282 330 { … … 301 349 /* Report back in any case. */ 302 350 CALLBACKPAYLOAD_FILE_NOTFIY_READ cplRead = { rc, (uint32_t)cbRead, pvDataRead }; 303 int rc2 = VbglR3GuestCtrlFileNotify( uClientId, ctx.uContextID, GUEST_FILE_NOTIFYTYPE_READ,304 &cplRead, sizeof(cplRead));351 int rc2 = VbglR3GuestCtrlFileNotify(pHostCtx->uClientID, pHostCtx->uContextID, 352 GUEST_FILE_NOTIFYTYPE_READ, &cplRead, sizeof(cplRead)); 305 353 if ( cbToRead > cbScratchBuf 306 354 && pvDataRead) … … 316 364 317 365 318 static int gstcntlSessionHandleFileWrite(uint32_t uClientId, uint32_t cParms, 366 static int gstcntlSessionHandleFileWrite(const PVBOXSERVICECTRLSESSION pSession, 367 PVBGLR3GUESTCTRLHOSTCTX pHostCtx, 319 368 void *pvScratchBuf, size_t cbScratchBuf) 320 369 { 370 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 371 AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER); 321 372 AssertPtrReturn(pvScratchBuf, VERR_INVALID_POINTER); 322 373 AssertPtrReturn(cbScratchBuf, VERR_INVALID_PARAMETER); … … 325 376 uint32_t cbToWrite; 326 377 327 VBGLR3GUESTCTRLHOSTCTX ctx = { uClientId, cParms }; 328 int rc = VbglR3GuestCtrlFileGetWrite(&ctx, &uHandle, 378 int rc = VbglR3GuestCtrlFileGetWrite(pHostCtx, &uHandle, 329 379 pvScratchBuf, cbScratchBuf, 330 380 &cbToWrite); … … 332 382 { 333 383 size_t cbWritten = 0; 334 PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile( uHandle);384 PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(pSession, uHandle); 335 385 if (pFile) 336 386 { … … 342 392 /* Report back in any case. */ 343 393 CALLBACKPAYLOAD_FILE_NOTFIY_WRITE cplWrite = { rc, (uint32_t)cbWritten }; 344 int rc2 = VbglR3GuestCtrlFileNotify( uClientId, ctx.uContextID, GUEST_FILE_NOTIFYTYPE_WRITE,345 &cplWrite, sizeof(cplWrite));394 int rc2 = VbglR3GuestCtrlFileNotify(pHostCtx->uClientID, pHostCtx->uContextID, 395 GUEST_FILE_NOTIFYTYPE_WRITE, &cplWrite, sizeof(cplWrite)); 346 396 if (RT_FAILURE(rc2)) 347 397 VBoxServiceError("Failed to report file write status, rc=%Rrc\n", rc2); … … 353 403 354 404 355 static int gstcntlSessionHandleFileWriteAt(uint32_t uClientId, uint32_t cParms, 405 static int gstcntlSessionHandleFileWriteAt(const PVBOXSERVICECTRLSESSION pSession, 406 PVBGLR3GUESTCTRLHOSTCTX pHostCtx, 356 407 void *pvScratchBuf, size_t cbScratchBuf) 357 408 { 409 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 410 AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER); 358 411 AssertPtrReturn(pvScratchBuf, VERR_INVALID_POINTER); 359 412 AssertPtrReturn(cbScratchBuf, VERR_INVALID_PARAMETER); … … 362 415 uint32_t cbToWrite; int64_t iOffset; 363 416 364 VBGLR3GUESTCTRLHOSTCTX ctx = { uClientId, cParms }; 365 int rc = VbglR3GuestCtrlFileGetWriteAt(&ctx, &uHandle, 417 int rc = VbglR3GuestCtrlFileGetWriteAt(pHostCtx, &uHandle, 366 418 pvScratchBuf, cbScratchBuf, 367 419 &cbToWrite, (uint64_t*)&iOffset); … … 369 421 { 370 422 size_t cbWritten = 0; 371 PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile( uHandle);423 PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(pSession, uHandle); 372 424 if (pFile) 373 425 { … … 380 432 /* Report back in any case. */ 381 433 CALLBACKPAYLOAD_FILE_NOTFIY_WRITE cplWrite = { rc, (uint32_t)cbWritten }; 382 int rc2 = VbglR3GuestCtrlFileNotify( uClientId, ctx.uContextID, GUEST_FILE_NOTIFYTYPE_WRITE,383 &cplWrite, sizeof(cplWrite));434 int rc2 = VbglR3GuestCtrlFileNotify(pHostCtx->uClientID, pHostCtx->uContextID, 435 GUEST_FILE_NOTIFYTYPE_WRITE, &cplWrite, sizeof(cplWrite)); 384 436 if (RT_FAILURE(rc2)) 385 437 VBoxServiceError("Failed to report file write status, rc=%Rrc\n", rc2); … … 391 443 392 444 393 static int gstcntlSessionHandleFileSeek(uint32_t uClientId, uint32_t cParms) 394 { 445 static int gstcntlSessionHandleFileSeek(const PVBOXSERVICECTRLSESSION pSession, 446 PVBGLR3GUESTCTRLHOSTCTX pHostCtx) 447 { 448 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 449 AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER); 450 395 451 uint32_t uHandle; 396 452 uint32_t uSeekMethod; … … 399 455 uint64_t uOffsetActual = 0; 400 456 401 VBGLR3GUESTCTRLHOSTCTX ctx = { uClientId, cParms }; 402 int rc = VbglR3GuestCtrlFileGetSeek(&ctx, &uHandle, 457 int rc = VbglR3GuestCtrlFileGetSeek(pHostCtx, &uHandle, 403 458 &uSeekMethod, &uOffset); 404 459 if (RT_SUCCESS(rc)) 405 460 { 406 PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile( uHandle);461 PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(pSession, uHandle); 407 462 if (pFile) 408 463 { … … 436 491 /* Report back in any case. */ 437 492 CALLBACKPAYLOAD_FILE_NOTFIY_SEEK cplSeek = { rc, uOffsetActual }; 438 int rc2 = VbglR3GuestCtrlFileNotify( uClientId, ctx.uContextID, GUEST_FILE_NOTIFYTYPE_SEEK,439 &cplSeek, sizeof(cplSeek));493 int rc2 = VbglR3GuestCtrlFileNotify(pHostCtx->uClientID, pHostCtx->uContextID, 494 GUEST_FILE_NOTIFYTYPE_SEEK, &cplSeek, sizeof(cplSeek)); 440 495 if (RT_FAILURE(rc2)) 441 496 VBoxServiceError("Failed to report file seek status, rc=%Rrc\n", rc2); … … 447 502 448 503 449 static int gstcntlSessionHandleFileTell(uint32_t uClientId, uint32_t cParms) 450 { 504 static int gstcntlSessionHandleFileTell(const PVBOXSERVICECTRLSESSION pSession, 505 PVBGLR3GUESTCTRLHOSTCTX pHostCtx) 506 { 507 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 508 AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER); 509 451 510 uint32_t uHandle; 452 511 uint64_t uOffsetActual = 0; 453 512 454 VBGLR3GUESTCTRLHOSTCTX ctx = { uClientId, cParms }; 455 int rc = VbglR3GuestCtrlFileGetTell(&ctx, &uHandle); 456 if (RT_SUCCESS(rc)) 457 { 458 PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(uHandle); 513 int rc = VbglR3GuestCtrlFileGetTell(pHostCtx, &uHandle); 514 if (RT_SUCCESS(rc)) 515 { 516 PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(pSession, uHandle); 459 517 if (pFile) 460 518 { … … 466 524 /* Report back in any case. */ 467 525 CALLBACKPAYLOAD_FILE_NOTFIY_TELL cplTell = { rc, uOffsetActual }; 468 int rc2 = VbglR3GuestCtrlFileNotify( uClientId, ctx.uContextID, GUEST_FILE_NOTIFYTYPE_TELL,469 &cplTell, sizeof(cplTell));526 int rc2 = VbglR3GuestCtrlFileNotify(pHostCtx->uClientID, pHostCtx->uContextID, 527 GUEST_FILE_NOTIFYTYPE_TELL, &cplTell, sizeof(cplTell)); 470 528 if (RT_FAILURE(rc2)) 471 529 VBoxServiceError("Failed to report file tell status, rc=%Rrc\n", rc2); … … 473 531 rc = rc2; 474 532 } 533 return rc; 534 } 535 536 537 /** 538 * Handles starting a guest processes. 539 * 540 * @returns IPRT status code. 541 * @param pSession Guest session. 542 * @param uClientID The HGCM client session ID. 543 * @param cParms The number of parameters the host is offering. 544 */ 545 int GstCntlSessionHandleProcExec(PVBOXSERVICECTRLSESSION pSession, 546 PVBGLR3GUESTCTRLHOSTCTX pHostCtx) 547 { 548 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 549 AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER); 550 551 int rc; 552 bool fStartAllowed = false; /* Flag indicating whether starting a process is allowed or not. */ 553 554 if ( (pHostCtx->uProtocol < 2 && pHostCtx->uNumParms == 11) 555 || (pHostCtx->uProtocol >= 2 && pHostCtx->uNumParms == 12) 556 ) 557 { 558 VBOXSERVICECTRLPROCSTARTUPINFO proc; 559 RT_ZERO(proc); 560 561 /* Initialize maximum environment block size -- needed as input 562 * parameter to retrieve the stuff from the host. On output this then 563 * will contain the actual block size. */ 564 proc.cbEnv = sizeof(proc.szEnv); 565 566 rc = VbglR3GuestCtrlProcGetStart(pHostCtx, 567 /* Command */ 568 proc.szCmd, sizeof(proc.szCmd), 569 /* Flags */ 570 &proc.uFlags, 571 /* Arguments */ 572 proc.szArgs, sizeof(proc.szArgs), &proc.uNumArgs, 573 /* Environment */ 574 proc.szEnv, &proc.cbEnv, &proc.uNumEnvVars, 575 /* Credentials; for hosts with VBox < 4.3. */ 576 proc.szUser, sizeof(proc.szUser), 577 proc.szPassword, sizeof(proc.szPassword), 578 /* Timelimit */ 579 &proc.uTimeLimitMS, 580 /* Process priority */ 581 &proc.uPriority, 582 /* Process affinity */ 583 proc.uAffinity, sizeof(proc.uAffinity), &proc.uNumAffinity); 584 if (RT_SUCCESS(rc)) 585 { 586 VBoxServiceVerbose(3, "Request to start process szCmd=%s, uFlags=0x%x, szArgs=%s, szEnv=%s, szUser=%s, szPassword=%s, uTimeout=%RU32\n", 587 proc.szCmd, proc.uFlags, 588 proc.uNumArgs ? proc.szArgs : "<None>", 589 proc.uNumEnvVars ? proc.szEnv : "<None>", 590 proc.szUser, 591 #ifdef DEBUG 592 proc.szPassword, 593 #else 594 "XXX", /* Never show passwords in release mode. */ 595 #endif 596 proc.uTimeLimitMS); 597 598 rc = GstCntlSessionReapThreads(pSession); 599 if (RT_FAILURE(rc)) 600 VBoxServiceError("Reaping stopped processes failed with rc=%Rrc\n", rc); 601 /* Keep going. */ 602 603 rc = GstCntlSessionProcessStartAllowed(pSession, &fStartAllowed); 604 if (RT_SUCCESS(rc)) 605 { 606 if (fStartAllowed) 607 { 608 rc = GstCntlProcessStart(pHostCtx->uContextID, &proc); 609 } 610 else 611 rc = VERR_MAX_PROCS_REACHED; /* Maximum number of processes reached. */ 612 } 613 } 614 } 615 else 616 rc = VERR_NOT_SUPPORTED; /* Unsupported number of parameters. */ 617 618 /* In case of an error we need to notify the host to not wait forever for our response. */ 619 if (RT_FAILURE(rc)) 620 { 621 VBoxServiceError("Starting process failed with rc=%Rrc\n", rc); 622 623 /* 624 * Note: The context ID can be 0 because we mabye weren't able to fetch the command 625 * from the host. The host in case has to deal with that! 626 */ 627 int rc2 = VbglR3GuestCtrlProcCbStatus(pHostCtx->uClientID, pHostCtx->uContextID, 628 0 /* PID, invalid */, 629 PROC_STS_ERROR, rc, 630 NULL /* pvData */, 0 /* cbData */); 631 if (RT_FAILURE(rc2)) 632 { 633 VBoxServiceError("Error sending start process status to host, rc=%Rrc\n", rc2); 634 if (RT_SUCCESS(rc)) 635 rc = rc2; 636 } 637 } 638 639 return rc; 640 } 641 642 643 /** 644 * Handles input for a started process by copying the received data into its 645 * stdin pipe. 646 * 647 * @returns IPRT status code. 648 * @param pvScratchBuf The scratch buffer. 649 * @param cbScratchBuf The scratch buffer size for retrieving the input data. 650 */ 651 int GstCntlSessionHandleProcInput(PVBOXSERVICECTRLSESSION pSession, 652 PVBGLR3GUESTCTRLHOSTCTX pHostCtx, 653 void *pvScratchBuf, size_t cbScratchBuf) 654 { 655 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 656 AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER); 657 AssertPtrReturn(cbScratchBuf, VERR_INVALID_PARAMETER); 658 AssertPtrReturn(pvScratchBuf, VERR_INVALID_POINTER); 659 660 uint32_t uPID; 661 uint32_t uFlags; 662 uint32_t cbSize; 663 664 uint32_t uStatus = INPUT_STS_UNDEFINED; /* Status sent back to the host. */ 665 uint32_t cbWritten = 0; /* Number of bytes written to the guest. */ 666 667 /* 668 * Ask the host for the input data. 669 */ 670 int rc = VbglR3GuestCtrlProcGetInput(pHostCtx, &uPID, &uFlags, 671 pvScratchBuf, cbScratchBuf, &cbSize); 672 if (RT_FAILURE(rc)) 673 { 674 VBoxServiceError("[PID %RU32]: Failed to retrieve exec input command! Error: %Rrc\n", 675 uPID, rc); 676 } 677 else if (cbSize > cbScratchBuf) 678 { 679 VBoxServiceError("[PID %RU32]: Too much input received! cbSize=%u, cbScratchBuf=%u\n", 680 uPID, cbSize, cbScratchBuf); 681 rc = VERR_INVALID_PARAMETER; 682 } 683 else 684 { 685 /* 686 * Is this the last input block we need to deliver? Then let the pipe know ... 687 */ 688 bool fPendingClose = false; 689 if (uFlags & INPUT_FLAG_EOF) 690 { 691 fPendingClose = true; 692 VBoxServiceVerbose(4, "[PID %RU32]: Got last input block of size %u ...\n", 693 uPID, cbSize); 694 } 695 696 rc = gstcntlSessionSetInput(pSession, uPID, 697 pHostCtx->uContextID, fPendingClose, pvScratchBuf, 698 cbSize, &cbWritten); 699 VBoxServiceVerbose(4, "[PID %RU32]: Written input, CID=%u, rc=%Rrc, uFlags=0x%x, fPendingClose=%d, cbSize=%u, cbWritten=%u\n", 700 uPID, pHostCtx->uContextID, rc, uFlags, fPendingClose, cbSize, cbWritten); 701 if (RT_SUCCESS(rc)) 702 { 703 uStatus = INPUT_STS_WRITTEN; 704 uFlags = 0; /* No flags at the moment. */ 705 } 706 else 707 { 708 if (rc == VERR_BAD_PIPE) 709 uStatus = INPUT_STS_TERMINATED; 710 else if (rc == VERR_BUFFER_OVERFLOW) 711 uStatus = INPUT_STS_OVERFLOW; 712 } 713 } 714 715 /* 716 * If there was an error and we did not set the host status 717 * yet, then do it now. 718 */ 719 if ( RT_FAILURE(rc) 720 && uStatus == INPUT_STS_UNDEFINED) 721 { 722 uStatus = INPUT_STS_ERROR; 723 uFlags = rc; 724 } 725 Assert(uStatus > INPUT_STS_UNDEFINED); 726 727 VBoxServiceVerbose(3, "[PID %RU32]: Input processed, CID=%u, uStatus=%u, uFlags=0x%x, cbWritten=%u\n", 728 uPID, pHostCtx->uContextID, uStatus, uFlags, cbWritten); 729 730 /* Note: Since the context ID is unique the request *has* to be completed here, 731 * regardless whether we got data or not! Otherwise the progress object 732 * on the host never will get completed! */ 733 rc = VbglR3GuestCtrlProcCbStatusInput(pHostCtx->uClientID, pHostCtx->uContextID, uPID, 734 uStatus, uFlags, (uint32_t)cbWritten); 735 736 if (RT_FAILURE(rc)) 737 VBoxServiceError("[PID %RU32]: Failed to report input status! Error: %Rrc\n", 738 uPID, rc); 739 return rc; 740 } 741 742 743 /** 744 * Handles the guest control output command. 745 * 746 * @return IPRT status code. 747 */ 748 int GstCntlSessionHandleProcOutput(PVBOXSERVICECTRLSESSION pSession, 749 PVBGLR3GUESTCTRLHOSTCTX pHostCtx) 750 { 751 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 752 AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER); 753 754 uint32_t uPID; 755 uint32_t uHandleID; 756 uint32_t uFlags; 757 758 int rc = VbglR3GuestCtrlProcGetOutput(pHostCtx, &uPID, &uHandleID, &uFlags); 759 if (RT_SUCCESS(rc)) 760 { 761 uint8_t *pBuf = (uint8_t*)RTMemAlloc(_64K); 762 if (pBuf) 763 { 764 uint32_t cbRead = 0; 765 rc = gstcntlSessionGetOutput(pSession, uPID, 766 pHostCtx->uContextID, uHandleID, RT_INDEFINITE_WAIT /* Timeout */, 767 pBuf, _64K /* cbSize */, &cbRead); 768 VBoxServiceVerbose(3, "[PID %RU32]: Got output, rc=%Rrc, CID=%u, cbRead=%u, uHandle=%u, uFlags=%u\n", 769 uPID, rc, pHostCtx->uContextID, cbRead, uHandleID, uFlags); 770 771 #ifdef DEBUG 772 if ( (pSession->uFlags & VBOXSERVICECTRLSESSION_FLAG_DUMPSTDOUT) 773 && (uHandleID == OUTPUT_HANDLE_ID_STDERR)) 774 { 775 char szDumpFile[RTPATH_MAX]; 776 if (!RTStrPrintf(szDumpFile, sizeof(szDumpFile), "VBoxService_Session%RU32_PID%RU32_StdOut.txt", 777 pSession->StartupInfo.uSessionID, uPID)) 778 rc = VERR_BUFFER_UNDERFLOW; 779 if (RT_SUCCESS(rc)) 780 rc = gstcntlSessionDumpToFile(szDumpFile, pBuf, cbRead); 781 } 782 else if ( (pSession->uFlags & VBOXSERVICECTRLSESSION_FLAG_DUMPSTDERR) 783 && ( uHandleID == OUTPUT_HANDLE_ID_STDOUT 784 || uHandleID == OUTPUT_HANDLE_ID_STDOUT_DEPRECATED)) 785 { 786 char szDumpFile[RTPATH_MAX]; 787 if (!RTStrPrintf(szDumpFile, sizeof(szDumpFile), "VBoxService_Session%RU32_PID%RU32_StdErr.txt", 788 pSession->StartupInfo.uSessionID, uPID)) 789 rc = VERR_BUFFER_UNDERFLOW; 790 if (RT_SUCCESS(rc)) 791 rc = gstcntlSessionDumpToFile(szDumpFile, pBuf, cbRead); 792 AssertRC(rc); 793 } 794 #endif 795 /** Note: Don't convert/touch/modify/whatever the output data here! This might be binary 796 * data which the host needs to work with -- so just pass through all data unfiltered! */ 797 798 /* Note: Since the context ID is unique the request *has* to be completed here, 799 * regardless whether we got data or not! Otherwise the progress object 800 * on the host never will get completed! */ 801 int rc2 = VbglR3GuestCtrlProcCbOutput(pHostCtx->uClientID, pHostCtx->uContextID, uPID, uHandleID, uFlags, 802 pBuf, cbRead); 803 if (RT_SUCCESS(rc)) 804 rc = rc2; 805 else if (rc == VERR_NOT_FOUND) /* It's not critical if guest process (PID) is not found. */ 806 rc = VINF_SUCCESS; 807 808 RTMemFree(pBuf); 809 } 810 else 811 rc = VERR_NO_MEMORY; 812 } 813 814 if (RT_FAILURE(rc)) 815 VBoxServiceError("[PID %RU32]: Error handling output command! Error: %Rrc\n", 816 uPID, rc); 817 return rc; 818 } 819 820 821 int GstCntlSessionHandleProcTerminate(const PVBOXSERVICECTRLSESSION pSession, 822 PVBGLR3GUESTCTRLHOSTCTX pHostCtx) 823 { 824 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 825 AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER); 826 827 uint32_t uPID; 828 int rc = VbglR3GuestCtrlProcGetTerminate(pHostCtx, &uPID); 829 if (RT_SUCCESS(rc)) 830 { 831 PVBOXSERVICECTRLREQUEST pRequest; 832 rc = GstCntlProcessRequestAllocEx(&pRequest, VBOXSERVICECTRLREQUEST_PROC_TERM, 833 NULL /* pvBuf */, 0 /* cbBuf */, pHostCtx->uContextID); 834 if (RT_SUCCESS(rc)) 835 { 836 PVBOXSERVICECTRLTHREAD pProcess = GstCntlSessionAcquireProcess(pSession, uPID); 837 if (pProcess) 838 { 839 rc = GstCntlProcessPerform(pProcess, pRequest); 840 GstCntlProcessRelease(pProcess); 841 } 842 else 843 rc = VERR_NOT_FOUND; 844 845 GstCntlProcessRequestFree(pRequest); 846 } 847 } 848 849 return rc; 850 } 851 852 853 int GstCntlSessionHandleProcWaitFor(const PVBOXSERVICECTRLSESSION pSession, 854 PVBGLR3GUESTCTRLHOSTCTX pHostCtx) 855 { 856 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 857 AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER); 858 859 uint32_t uPID; 860 uint32_t uWaitFlags; uint32_t uTimeoutMS; 861 862 int rc = VbglR3GuestCtrlProcGetWaitFor(pHostCtx, &uPID, &uWaitFlags, &uTimeoutMS); 863 if (RT_SUCCESS(rc)) 864 { 865 PVBOXSERVICECTRLREQUEST pRequest; 866 VBOXSERVICECTRLREQDATA_WAIT_FOR reqData = { uWaitFlags, uTimeoutMS }; 867 rc = GstCntlProcessRequestAllocEx(&pRequest, VBOXSERVICECTRLREQUEST_WAIT_FOR, 868 &reqData, sizeof(reqData), pHostCtx->uContextID); 869 if (RT_SUCCESS(rc)) 870 { 871 PVBOXSERVICECTRLTHREAD pProcess = GstCntlSessionAcquireProcess(pSession, uPID); 872 if (pProcess) 873 { 874 rc = GstCntlProcessPerform(pProcess, pRequest); 875 GstCntlProcessRelease(pProcess); 876 } 877 else 878 rc = VERR_NOT_FOUND; 879 880 GstCntlProcessRequestFree(pRequest); 881 } 882 } 883 884 return rc; 885 } 886 887 888 int GstCntlSessionHandler(PVBOXSERVICECTRLSESSION pSession, 889 uint32_t uMsg, PVBGLR3GUESTCTRLHOSTCTX pHostCtx, 890 void *pvScratchBuf, size_t cbScratchBuf, 891 volatile bool *pfShutdown) 892 { 893 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 894 AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER); 895 AssertPtrReturn(pvScratchBuf, VERR_INVALID_POINTER); 896 AssertPtrReturn(pfShutdown, VERR_INVALID_POINTER); 897 898 int rc; 899 900 switch (uMsg) 901 { 902 case HOST_CANCEL_PENDING_WAITS: 903 VBoxServiceVerbose(1, "We were asked to quit ...\n"); 904 /* Fall thru is intentional. */ 905 case HOST_SESSION_CLOSE: 906 /* Shutdown this fork. */ 907 rc = gstcntlSessionForkShutdown(pSession); 908 *pfShutdown = true; /* Shutdown in any case. */ 909 break; 910 911 case HOST_EXEC_CMD: 912 rc = GstCntlSessionHandleProcExec(pSession, pHostCtx); 913 break; 914 915 case HOST_EXEC_SET_INPUT: 916 rc = GstCntlSessionHandleProcInput(pSession, pHostCtx, 917 pvScratchBuf, cbScratchBuf); 918 break; 919 920 case HOST_EXEC_GET_OUTPUT: 921 rc = GstCntlSessionHandleProcOutput(pSession, pHostCtx); 922 break; 923 924 case HOST_EXEC_TERMINATE: 925 rc = GstCntlSessionHandleProcTerminate(pSession, pHostCtx); 926 break; 927 928 case HOST_EXEC_WAIT_FOR: 929 rc = GstCntlSessionHandleProcWaitFor(pSession, pHostCtx); 930 break; 931 932 case HOST_FILE_OPEN: 933 rc = gstcntlSessionHandleFileOpen(pSession, pHostCtx); 934 break; 935 936 case HOST_FILE_CLOSE: 937 rc = gstcntlSessionHandleFileClose(pSession, pHostCtx); 938 break; 939 940 case HOST_FILE_READ: 941 rc = gstcntlSessionHandleFileRead(pSession, pHostCtx, 942 pvScratchBuf, cbScratchBuf); 943 break; 944 945 case HOST_FILE_READ_AT: 946 rc = gstcntlSessionHandleFileReadAt(pSession, pHostCtx, 947 pvScratchBuf, cbScratchBuf); 948 break; 949 950 case HOST_FILE_WRITE: 951 rc = gstcntlSessionHandleFileWrite(pSession, pHostCtx, 952 pvScratchBuf, cbScratchBuf); 953 break; 954 955 case HOST_FILE_WRITE_AT: 956 rc = gstcntlSessionHandleFileWriteAt(pSession, pHostCtx, 957 pvScratchBuf, cbScratchBuf); 958 break; 959 960 case HOST_FILE_SEEK: 961 rc = gstcntlSessionHandleFileSeek(pSession, pHostCtx); 962 break; 963 964 case HOST_FILE_TELL: 965 rc = gstcntlSessionHandleFileTell(pSession, pHostCtx); 966 break; 967 968 default: 969 VBoxServiceVerbose(3, "Unsupported message from host, uMsg=%RU32, cParms=%RU32\n", 970 uMsg, pHostCtx->uNumParms); 971 /* Don't terminate here; just wait for the next message. */ 972 break; 973 } 974 475 975 return rc; 476 976 } … … 489 989 static DECLCALLBACK(int) gstcntlSessionThread(RTTHREAD ThreadSelf, void *pvUser) 490 990 { 491 PVBOXSERVICECTRLSESSION pSession = (PVBOXSERVICECTRLSESSION)pvUser;991 PVBOXSERVICECTRLSESSIONTHREAD pSession = (PVBOXSERVICECTRLSESSIONTHREAD)pvUser; 492 992 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 493 993 … … 532 1032 533 1033 534 RTEXITCODE gstcntlSessionWorker(void) 535 { 1034 RTEXITCODE gstcntlSessionWorker(PVBOXSERVICECTRLSESSION pSession) 1035 { 1036 AssertPtrReturn(pSession, RTEXITCODE_SYNTAX); 1037 536 1038 bool fSessionFilter = true; 537 1039 538 1040 VBoxServiceVerbose(0, "Hi, this is guest session ID=%RU32\n", 539 g_uSessionID);1041 pSession->StartupInfo.uSessionID); 540 1042 541 1043 uint32_t uClientID; … … 544 1046 { 545 1047 /* Set session filter. */ 546 uint32_t uFilterAdd = VBOX_GUESTCTRL_CONTEXTID_MAKE_SESSION(g_uSessionID); 1048 uint32_t uFilterAdd = 1049 VBOX_GUESTCTRL_CONTEXTID_MAKE_SESSION(pSession->StartupInfo.uSessionID); 547 1050 548 1051 rc = VbglR3GuestCtrlMsgSetFilter(uClientID, uFilterAdd, 0 /* Filter remove */); … … 558 1061 rc = VINF_SUCCESS; 559 1062 } 560 } 1063 1064 VBoxServiceVerbose(1, "Using client ID=%RU32\n", uClientID); 1065 } 1066 else 1067 VBoxServiceError("Error connecting to guest control service, rc=%Rrc\n", rc); 561 1068 562 1069 /* Allocate a scratch buffer for commands which also send … … 568 1075 if (RT_SUCCESS(rc)) 569 1076 { 570 RTListInit(&g_lstSessionFiles);571 1077 pvScratchBuf = (uint8_t*)RTMemAlloc(cbScratchBuf); 572 1078 if (!pvScratchBuf) … … 578 1084 bool fShutdown = false; 579 1085 1086 VBGLR3GUESTCTRLHOSTCTX ctxHost = { uClientID, 1087 pSession->StartupInfo.uProtocol }; 580 1088 for (;;) 581 1089 { … … 595 1103 VBoxServiceVerbose(3, "Msg=%RU32 (%RU32 parms) retrieved\n", uMsg, cParms); 596 1104 597 /** @todo Guest session ID change detection? */ 598 599 switch (uMsg) 600 { 601 case HOST_CANCEL_PENDING_WAITS: 602 /* Fall thru is intentional. */ 603 case HOST_SESSION_CLOSE: 604 /* Shutdown this fork. */ 605 rc = gstcntlSessionForkShutdown(uClientID, cParms); 606 fShutdown = true; /* Shutdown in any case. */ 607 break; 608 609 case HOST_FILE_OPEN: 610 rc = gstcntlSessionHandleFileOpen(uClientID, cParms); 611 break; 612 613 case HOST_FILE_CLOSE: 614 rc = gstcntlSessionHandleFileClose(uClientID, cParms); 615 break; 616 617 case HOST_FILE_READ: 618 rc = gstcntlSessionHandleFileRead(uClientID, cParms, 619 pvScratchBuf, cbScratchBuf); 620 break; 621 622 case HOST_FILE_READ_AT: 623 rc = gstcntlSessionHandleFileReadAt(uClientID, cParms, 624 pvScratchBuf, cbScratchBuf); 625 break; 626 627 case HOST_FILE_WRITE: 628 rc = gstcntlSessionHandleFileWrite(uClientID, cParms, 629 pvScratchBuf, cbScratchBuf); 630 break; 631 632 case HOST_FILE_WRITE_AT: 633 rc = gstcntlSessionHandleFileWriteAt(uClientID, cParms, 634 pvScratchBuf, cbScratchBuf); 635 break; 636 637 case HOST_FILE_SEEK: 638 rc = gstcntlSessionHandleFileSeek(uClientID, cParms); 639 break; 640 641 case HOST_FILE_TELL: 642 rc = gstcntlSessionHandleFileTell(uClientID, cParms); 643 break; 644 645 default: 646 VBoxServiceVerbose(3, "Unsupported message from host, uMsg=%RU32, cParms=%RU32\n", 647 uMsg, cParms); 648 /* Don't terminate here; just wait for the next message. */ 649 break; 650 } 1105 rc = GstCntlSessionHandler(pSession, uMsg, &ctxHost, 1106 pvScratchBuf, cbScratchBuf, &fShutdown); 651 1107 } 652 1108 … … 659 1115 } 660 1116 661 VBoxServiceVerbose(0, "Session %RU32 ended\n", g_uSessionID);1117 VBoxServiceVerbose(0, "Session %RU32 ended\n", pSession->StartupInfo.uSessionID); 662 1118 663 1119 if (pvScratchBuf) … … 669 1125 VBoxServiceVerbose(3, "Session worker returned with rc=%Rrc\n", rc); 670 1126 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; 1127 } 1128 1129 1130 /** 1131 * Finds a (formerly) started guest process given by its PID and locks it. 1132 * Must be unlocked by the caller with GstCntlProcessRelease(). 1133 * 1134 * @return PVBOXSERVICECTRLTHREAD Locked guest process if found, otherwise NULL. 1135 * @param PVBOXSERVICECTRLSESSION Pointer to guest session where to search process in. 1136 * @param uPID PID to search for. 1137 */ 1138 PVBOXSERVICECTRLTHREAD GstCntlSessionAcquireProcess(PVBOXSERVICECTRLSESSION pSession, uint32_t uPID) 1139 { 1140 AssertPtrReturn(pSession, NULL); 1141 1142 PVBOXSERVICECTRLTHREAD pThread = NULL; 1143 int rc = RTCritSectEnter(&pSession->csControlThreads); 1144 if (RT_SUCCESS(rc)) 1145 { 1146 PVBOXSERVICECTRLTHREAD pThreadCur; 1147 RTListForEach(&pSession->lstControlThreadsActive, pThreadCur, VBOXSERVICECTRLTHREAD, Node) 1148 { 1149 if (pThreadCur->uPID == uPID) 1150 { 1151 rc = RTCritSectEnter(&pThreadCur->CritSect); 1152 if (RT_SUCCESS(rc)) 1153 pThread = pThreadCur; 1154 break; 1155 } 1156 } 1157 1158 int rc2 = RTCritSectLeave(&pSession->csControlThreads); 1159 if (RT_SUCCESS(rc)) 1160 rc = rc2; 1161 } 1162 1163 return pThread; 1164 } 1165 1166 1167 int GstCntlSessionCloseAll(PVBOXSERVICECTRLSESSION pSession) 1168 { 1169 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 1170 1171 /* Signal all threads in the active list that we want to shutdown. */ 1172 PVBOXSERVICECTRLTHREAD pThread; 1173 RTListForEach(&pSession->lstControlThreadsActive, pThread, VBOXSERVICECTRLTHREAD, Node) 1174 GstCntlProcessStop(pThread); 1175 1176 /* Wait for all active threads to shutdown and destroy the active thread list. */ 1177 pThread = RTListGetFirst(&pSession->lstControlThreadsActive, VBOXSERVICECTRLTHREAD, Node); 1178 while (pThread) 1179 { 1180 PVBOXSERVICECTRLTHREAD pNext = RTListNodeGetNext(&pThread->Node, VBOXSERVICECTRLTHREAD, Node); 1181 bool fLast = RTListNodeIsLast(&pSession->lstControlThreadsActive, &pThread->Node); 1182 1183 int rc2 = GstCntlProcessWait(pThread, 1184 30 * 1000 /* Wait 30 seconds max. */, 1185 NULL /* rc */); 1186 if (RT_FAILURE(rc2)) 1187 { 1188 VBoxServiceError("Guest process thread failed to stop; rc=%Rrc\n", rc2); 1189 /* Keep going. */ 1190 } 1191 1192 if (fLast) 1193 break; 1194 1195 pThread = pNext; 1196 } 1197 1198 int rc = GstCntlSessionReapThreads(pSession); 1199 if (RT_FAILURE(rc)) 1200 VBoxServiceError("Reaping inactive threads failed with rc=%Rrc\n", rc); 1201 1202 AssertMsg(RTListIsEmpty(&pSession->lstControlThreadsActive), 1203 ("Guest process active thread list still contains entries when it should not\n")); 1204 AssertMsg(RTListIsEmpty(&pSession->lstControlThreadsInactive), 1205 ("Guest process inactive thread list still contains entries when it should not\n")); 1206 1207 return rc; 1208 } 1209 1210 1211 int GstCntlSessionDestroy(PVBOXSERVICECTRLSESSION pSession) 1212 { 1213 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 1214 1215 int rc = GstCntlSessionCloseAll(pSession); 1216 1217 /* Destroy critical section. */ 1218 RTCritSectDelete(&pSession->csControlThreads); 1219 1220 return rc; 1221 } 1222 1223 1224 /** 1225 * Gets output from stdout/stderr of a specified guest process. 1226 * 1227 * @return IPRT status code. 1228 * @param pSession Guest session. 1229 * @param uPID PID of process to retrieve the output from. 1230 * @param uCID Context ID. 1231 * @param uHandleId Stream ID (stdout = 0, stderr = 2) to get the output from. 1232 * @param cMsTimeout Timeout (in ms) to wait for output becoming 1233 * available. 1234 * @param pvBuf Pointer to a pre-allocated buffer to store the output. 1235 * @param cbBuf Size (in bytes) of the pre-allocated buffer. 1236 * @param pcbRead Pointer to number of bytes read. Optional. 1237 */ 1238 static int gstcntlSessionGetOutput(const PVBOXSERVICECTRLSESSION pSession, 1239 uint32_t uPID, uint32_t uCID, 1240 uint32_t uHandleId, uint32_t cMsTimeout, 1241 void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead) 1242 { 1243 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 1244 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); 1245 AssertReturn(cbBuf, VERR_INVALID_PARAMETER); 1246 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER); 1247 1248 int rc = VINF_SUCCESS; 1249 VBOXSERVICECTRLREQUESTTYPE reqType = VBOXSERVICECTRLREQUEST_UNKNOWN; /* (gcc maybe, well, wrong.) */ 1250 switch (uHandleId) 1251 { 1252 case OUTPUT_HANDLE_ID_STDERR: 1253 reqType = VBOXSERVICECTRLREQUEST_PROC_STDERR; 1254 break; 1255 1256 case OUTPUT_HANDLE_ID_STDOUT: 1257 case OUTPUT_HANDLE_ID_STDOUT_DEPRECATED: 1258 reqType = VBOXSERVICECTRLREQUEST_PROC_STDOUT; 1259 break; 1260 1261 default: 1262 rc = VERR_INVALID_PARAMETER; 1263 break; 1264 } 1265 1266 if (RT_SUCCESS(rc)) 1267 { 1268 PVBOXSERVICECTRLREQUEST pRequest; 1269 rc = GstCntlProcessRequestAllocEx(&pRequest, reqType, pvBuf, cbBuf, uCID); 1270 if (RT_SUCCESS(rc)) 1271 { 1272 PVBOXSERVICECTRLTHREAD pProcess = GstCntlSessionAcquireProcess(pSession, uPID); 1273 if (pProcess) 1274 { 1275 rc = GstCntlProcessPerform(pProcess, pRequest); 1276 GstCntlProcessRelease(pProcess); 1277 } 1278 else 1279 rc = VERR_NOT_FOUND; 1280 1281 if (RT_SUCCESS(rc) && pcbRead) 1282 *pcbRead = pRequest->cbData; 1283 GstCntlProcessRequestFree(pRequest); 1284 } 1285 } 1286 1287 return rc; 1288 } 1289 1290 1291 int GstCntlSessionInit(PVBOXSERVICECTRLSESSION pSession, uint32_t uFlags) 1292 { 1293 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 1294 1295 RTListInit(&pSession->lstControlThreadsActive); 1296 RTListInit(&pSession->lstControlThreadsInactive); 1297 RTListInit(&pSession->lstFiles); 1298 1299 pSession->uFlags = uFlags; 1300 1301 if (pSession->uFlags & VBOXSERVICECTRLSESSION_FLAG_FORK) 1302 { 1303 /* Protocol must be specified explicitly. */ 1304 pSession->StartupInfo.uProtocol = UINT32_MAX; 1305 1306 /* Session ID must be specified explicitly. */ 1307 pSession->StartupInfo.uSessionID = UINT32_MAX; 1308 } 1309 1310 /* Init critical section for protecting the thread lists. */ 1311 int rc = RTCritSectInit(&pSession->csControlThreads); 1312 AssertRC(rc); 1313 1314 return rc; 1315 } 1316 1317 1318 /** 1319 * Sets the specified guest thread to a certain list. 1320 ** @todo Still needed? 1321 * 1322 * @return IPRT status code. 1323 * @param enmList List to move thread to. 1324 * @param pThread Thread to set inactive. 1325 */ 1326 int GstCntlSessionListSet(PVBOXSERVICECTRLSESSION pSession, 1327 VBOXSERVICECTRLTHREADLISTTYPE enmList, 1328 PVBOXSERVICECTRLTHREAD pThread) 1329 { 1330 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 1331 AssertReturn(enmList > VBOXSERVICECTRLTHREADLIST_UNKNOWN, VERR_INVALID_PARAMETER); 1332 AssertPtrReturn(pThread, VERR_INVALID_POINTER); 1333 1334 int rc = RTCritSectEnter(&pSession->csControlThreads); 1335 if (RT_SUCCESS(rc)) 1336 { 1337 VBoxServiceVerbose(3, "Setting thread (PID %RU32) to list %d\n", 1338 pThread->uPID, enmList); 1339 1340 PRTLISTANCHOR pAnchor = NULL; 1341 switch (enmList) 1342 { 1343 case VBOXSERVICECTRLTHREADLIST_STOPPED: 1344 pAnchor = &pSession->lstControlThreadsInactive; 1345 break; 1346 1347 case VBOXSERVICECTRLTHREADLIST_RUNNING: 1348 pAnchor = &pSession->lstControlThreadsActive; 1349 break; 1350 1351 default: 1352 AssertMsgFailed(("Unknown list type: %u", enmList)); 1353 break; 1354 } 1355 1356 if (!pAnchor) 1357 rc = VERR_INVALID_PARAMETER; 1358 1359 if (RT_SUCCESS(rc)) 1360 { 1361 if (pThread->pAnchor != NULL) 1362 { 1363 /* If thread was assigned to a list before, 1364 * remove the thread from the old list first. */ 1365 /* rc = */ RTListNodeRemove(&pThread->Node); 1366 } 1367 1368 /* Add thread to desired list. */ 1369 /* rc = */ RTListAppend(pAnchor, &pThread->Node); 1370 pThread->pAnchor = pAnchor; 1371 } 1372 1373 int rc2 = RTCritSectLeave(&pSession->csControlThreads); 1374 if (RT_SUCCESS(rc)) 1375 rc = rc2; 1376 } 1377 1378 return VINF_SUCCESS; 1379 } 1380 1381 1382 1383 1384 1385 /** 1386 * Determines whether starting a new guest process according to the 1387 * maximum number of concurrent guest processes defined is allowed or not. 1388 * 1389 * @return IPRT status code. 1390 * @param pbAllowed True if starting (another) guest process 1391 * is allowed, false if not. 1392 */ 1393 int GstCntlSessionProcessStartAllowed(const PVBOXSERVICECTRLSESSION pSession, 1394 bool *pbAllowed) 1395 { 1396 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 1397 AssertPtrReturn(pbAllowed, VERR_INVALID_POINTER); 1398 1399 int rc = RTCritSectEnter(&pSession->csControlThreads); 1400 if (RT_SUCCESS(rc)) 1401 { 1402 /* 1403 * Check if we're respecting our memory policy by checking 1404 * how many guest processes are started and served already. 1405 */ 1406 bool fLimitReached = false; 1407 if (pSession->uProcsMaxKept) /* If we allow unlimited processes (=0), take a shortcut. */ 1408 { 1409 uint32_t uProcsRunning = 0; 1410 PVBOXSERVICECTRLTHREAD pThread; 1411 RTListForEach(&pSession->lstControlThreadsActive, pThread, VBOXSERVICECTRLTHREAD, Node) 1412 uProcsRunning++; 1413 1414 VBoxServiceVerbose(3, "Maximum served guest processes set to %u, running=%u\n", 1415 pSession->uProcsMaxKept, uProcsRunning); 1416 1417 int32_t iProcsLeft = (pSession->uProcsMaxKept - uProcsRunning - 1); 1418 if (iProcsLeft < 0) 1419 { 1420 VBoxServiceVerbose(3, "Maximum running guest processes reached (%u)\n", 1421 pSession->uProcsMaxKept); 1422 fLimitReached = true; 1423 } 1424 } 1425 1426 *pbAllowed = !fLimitReached; 1427 1428 int rc2 = RTCritSectLeave(&pSession->csControlThreads); 1429 if (RT_SUCCESS(rc)) 1430 rc = rc2; 1431 } 1432 1433 return rc; 1434 } 1435 1436 1437 /** 1438 * Reaps all inactive guest process threads. 1439 * 1440 * @return IPRT status code. 1441 */ 1442 int GstCntlSessionReapThreads(PVBOXSERVICECTRLSESSION pSession) 1443 { 1444 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 1445 1446 int rc = RTCritSectEnter(&pSession->csControlThreads); 1447 if (RT_SUCCESS(rc)) 1448 { 1449 PVBOXSERVICECTRLTHREAD pThread = 1450 RTListGetFirst(&pSession->lstControlThreadsInactive, VBOXSERVICECTRLTHREAD, Node); 1451 while (pThread) 1452 { 1453 PVBOXSERVICECTRLTHREAD pNext = RTListNodeGetNext(&pThread->Node, VBOXSERVICECTRLTHREAD, Node); 1454 bool fLast = RTListNodeIsLast(&pSession->lstControlThreadsInactive, &pThread->Node); 1455 int rc2 = GstCntlProcessWait(pThread, 30 * 1000 /* 30 seconds max. */, 1456 NULL /* rc */); 1457 if (RT_SUCCESS(rc2)) 1458 { 1459 RTListNodeRemove(&pThread->Node); 1460 1461 rc2 = GstCntlProcessFree(pThread); 1462 if (RT_FAILURE(rc2)) 1463 { 1464 VBoxServiceError("Freeing guest process thread failed with rc=%Rrc\n", rc2); 1465 if (RT_SUCCESS(rc)) /* Keep original failure. */ 1466 rc = rc2; 1467 } 1468 } 1469 else 1470 VBoxServiceError("Waiting on guest process thread failed with rc=%Rrc\n", rc2); 1471 /* Keep going. */ 1472 1473 if (fLast) 1474 break; 1475 1476 pThread = pNext; 1477 } 1478 1479 int rc2 = RTCritSectLeave(&pSession->csControlThreads); 1480 if (RT_SUCCESS(rc)) 1481 rc = rc2; 1482 } 1483 1484 VBoxServiceVerbose(4, "Reaping threads returned with rc=%Rrc\n", rc); 1485 return rc; 1486 } 1487 1488 1489 /** 1490 * Injects input to a specified running guest process. 1491 * 1492 * @return IPRT status code. 1493 * @param pSession Guest session. 1494 * @param uPID PID of process to set the input for. 1495 * @param uCID Context ID to use for reporting back. 1496 * @param fPendingClose Flag indicating whether this is the last input block sent to the process. 1497 * @param pvBuf Pointer to a buffer containing the actual input data. 1498 * @param cbBuf Size (in bytes) of the input buffer data. 1499 * @param pcbWritten Pointer to number of bytes written to the process. Optional. 1500 */ 1501 int gstcntlSessionSetInput(const PVBOXSERVICECTRLSESSION pSession, 1502 uint32_t uPID, uint32_t uCID, 1503 bool fPendingClose, 1504 void *pvBuf, uint32_t cbBuf, 1505 uint32_t *pcbWritten) 1506 { 1507 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 1508 /* pvBuf is optional. */ 1509 /* cbBuf is optional. */ 1510 /* pcbWritten is optional. */ 1511 1512 PVBOXSERVICECTRLREQUEST pRequest; 1513 int rc = GstCntlProcessRequestAllocEx(&pRequest, 1514 fPendingClose 1515 ? VBOXSERVICECTRLREQUEST_PROC_STDIN_EOF 1516 : VBOXSERVICECTRLREQUEST_PROC_STDIN, 1517 pvBuf, cbBuf, uCID); 1518 if (RT_SUCCESS(rc)) 1519 { 1520 PVBOXSERVICECTRLTHREAD pProcess = GstCntlSessionAcquireProcess(pSession, uPID); 1521 if (pProcess) 1522 { 1523 rc = GstCntlProcessPerform(pProcess, pRequest); 1524 GstCntlProcessRelease(pProcess); 1525 } 1526 else 1527 rc = VERR_NOT_FOUND; 1528 1529 if (RT_SUCCESS(rc)) 1530 { 1531 if (pcbWritten) 1532 *pcbWritten = pRequest->cbData; 1533 } 1534 1535 GstCntlProcessRequestFree(pRequest); 1536 } 1537 1538 return rc; 671 1539 } 672 1540 … … 678 1546 * 679 1547 * @return IPRT status code. 1548 * @param pList Which list to use to store the session thread in. 680 1549 * @param pSessionStartupInfo Session startup info. 681 * @param p Node Returns newly created session nodeon success.1550 * @param ppSessionThread Returns newly created session thread on success. 682 1551 * Optional. 683 1552 */ 684 int GstCntlSessionOpen(const PVBOXSERVICECTRLSESSIONSTARTUPINFO pSessionStartupInfo, 685 PRTLISTNODE pNode) 686 { 1553 int GstCntlSessionThreadOpen(PRTLISTANCHOR pList, 1554 const PVBOXSERVICECTRLSESSIONSTARTUPINFO pSessionStartupInfo, 1555 PVBOXSERVICECTRLSESSIONTHREAD *ppSessionThread) 1556 { 1557 AssertPtrReturn(pList, VERR_INVALID_POINTER); 687 1558 AssertPtrReturn(pSessionStartupInfo, VERR_INVALID_POINTER); 688 /* p Nodeis optional. */1559 /* ppSessionThread is optional. */ 689 1560 690 1561 #ifdef DEBUG 691 PVBOXSERVICECTRLSESSION pSessionCur;1562 PVBOXSERVICECTRLSESSIONTHREAD pSessionCur; 692 1563 /* Check for existing session in debug mode. Should never happen because of 693 1564 * Main consistency. */ 694 RTListForEach( &g_lstControlSessions, pSessionCur, VBOXSERVICECTRLSESSION, Node)1565 RTListForEach(pList, pSessionCur, VBOXSERVICECTRLSESSIONTHREAD, Node) 695 1566 { 696 1567 if (pSessionCur->StartupInfo.uSessionID == pSessionStartupInfo->uSessionID) … … 704 1575 int rc = VINF_SUCCESS; 705 1576 706 PVBOXSERVICECTRLSESSION pSession = (PVBOXSERVICECTRLSESSION)RTMemAllocZ(sizeof(VBOXSERVICECTRLSESSION));1577 PVBOXSERVICECTRLSESSIONTHREAD pSession = (PVBOXSERVICECTRLSESSIONTHREAD)RTMemAllocZ(sizeof(VBOXSERVICECTRLSESSIONTHREAD)); 707 1578 if (pSession) 708 1579 { … … 968 1839 969 1840 /* Add session to list. */ 970 /* rc = */ RTListAppend( &g_lstControlSessions, &pSession->Node);971 if (p Node) /* Return nodeif wanted. */972 pNode = &pSession->Node;1841 /* rc = */ RTListAppend(pList, &pSession->Node); 1842 if (ppSessionThread) /* Return session if wanted. */ 1843 *ppSessionThread = pSession; 973 1844 } 974 1845 } … … 996 1867 * @param uFlags Closing flags. 997 1868 */ 998 int GstCntlSession Close(PVBOXSERVICECTRLSESSIONpSession, uint32_t uFlags)1869 int GstCntlSessionThreadClose(PVBOXSERVICECTRLSESSIONTHREAD pSession, uint32_t uFlags) 999 1870 { 1000 1871 AssertPtrReturn(pSession, VERR_INVALID_POINTER); … … 1012 1883 uint32_t cMsTimeout = 30 * 1000; /* 30 seconds. */ 1013 1884 1014 VBoxServiceVerbose(3, "Waiting for session ID=%RU32 to close (%RU32ms) ...\n",1885 VBoxServiceVerbose(3, "Waiting for session thread ID=%RU32 to close (%RU32ms) ...\n", 1015 1886 pSession->StartupInfo.uSessionID, cMsTimeout); 1016 1887 … … 1019 1890 if (RT_FAILURE(rc)) 1020 1891 { 1021 VBoxServiceError("Waiting for session ID=%RU32 to close failed with rc=%Rrc\n", rc); 1892 VBoxServiceError("Waiting for session thread ID=%RU32 to close failed with rc=%Rrc\n", 1893 pSession->StartupInfo.uSessionID, rc); 1022 1894 } 1023 1895 else 1024 1896 { 1025 1897 fAlive = false; 1026 VBoxServiceVerbose(3, "Session ID=%RU32 threadended with rc=%Rrc\n",1898 VBoxServiceVerbose(3, "Session thread ID=%RU32 ended with rc=%Rrc\n", 1027 1899 pSession->StartupInfo.uSessionID, rcThread); 1028 1900 } … … 1053 1925 RTThreadSleep(100); /* Wait a bit. */ 1054 1926 } 1055 #endif 1056 1927 #endif 1057 1928 if (fAlive) 1058 1929 { 1059 VBoxServiceVerbose(3, "Session ID=%RU32 still alive, killing ...\n",1930 VBoxServiceVerbose(3, "Session thread ID=%RU32 still alive, killing ...\n", 1060 1931 pSession->StartupInfo.uSessionID); 1061 int rc2 = GstCntlSessionT erminate(pSession);1932 int rc2 = GstCntlSessionThreadTerminate(pSession); 1062 1933 if (RT_SUCCESS(rc)) 1063 1934 rc = rc2; … … 1079 1950 1080 1951 /** 1081 * Close all formerly opened guest session s.1952 * Close all formerly opened guest session threads. 1082 1953 * 1083 1954 * @return IPRT status code. 1955 * @param pList Which list to close the session threads for. 1084 1956 * @param uFlags Closing flags. 1085 1957 */ 1086 int GstCntlSessionCloseAll(uint32_t uFlags) 1087 { 1958 int GstCntlSessionThreadCloseAll(PRTLISTANCHOR pList, uint32_t uFlags) 1959 { 1960 AssertPtrReturn(pList, VERR_INVALID_POINTER); 1961 1088 1962 int rc = VINF_SUCCESS; 1089 1963 1090 PVBOXSERVICECTRLSESSION pSessionCur;1091 RTListForEach( &g_lstControlSessions, pSessionCur, VBOXSERVICECTRLSESSION, Node)1092 { 1093 int rc2 = GstCntlSession Close(pSessionCur, uFlags);1964 PVBOXSERVICECTRLSESSIONTHREAD pSessionCur; 1965 RTListForEach(pList, pSessionCur, VBOXSERVICECTRLSESSIONTHREAD, Node) 1966 { 1967 int rc2 = GstCntlSessionThreadClose(pSessionCur, uFlags); 1094 1968 if (RT_SUCCESS(rc)) 1095 1969 { … … 1104 1978 1105 1979 /** 1106 * Terminates a formerly opened guest session . Only1980 * Terminates a formerly opened guest session thread. Only 1107 1981 * use this as a last action! 1108 1982 * … … 1110 1984 * @param pSession Guest session to terminate. 1111 1985 */ 1112 int GstCntlSessionTerminate(PVBOXSERVICECTRLSESSION pSession) 1113 { 1114 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 1986 int GstCntlSessionThreadTerminate(PVBOXSERVICECTRLSESSIONTHREAD pSession) 1987 { 1988 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 1989 1990 if (pSession->hProcess == NIL_RTPROCESS) 1991 return VINF_SUCCESS; /* Nothing to terminate. */ 1115 1992 1116 1993 int rc; 1117 1118 1994 for (int i = 0; i < 3; i++) 1119 1995 { … … 1148 2024 int rc = VINF_SUCCESS; 1149 2025 2026 uint32_t uSessionFlags = VBOXSERVICECTRLSESSION_FLAG_FORK; 2027 1150 2028 while ( (ch = RTGetOpt(&GetState, &ValueUnion)) 1151 2029 && RT_SUCCESS(rc)) … … 1165 2043 1166 2044 case VBOXSERVICESESSIONOPT_SESSION_ID: 1167 g_ uSessionID = ValueUnion.u32;2045 g_Session.StartupInfo.uSessionID = ValueUnion.u32; 1168 2046 break; 1169 2047 1170 2048 case VBOXSERVICESESSIONOPT_SESSION_PROTO: 1171 g_ uSessionProto= ValueUnion.u32;2049 g_Session.StartupInfo.uProtocol = ValueUnion.u32; 1172 2050 break; 1173 2051 … … 1191 2069 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Initialization failed with rc=%Rrc", rc); 1192 2070 1193 if (g_uSessionID == UINT32_MAX) 2071 /* Init the session object. */ 2072 rc = GstCntlSessionInit(&g_Session, uSessionFlags); 2073 2074 if (g_Session.StartupInfo.uProtocol == UINT32_MAX) 2075 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No protocol version specified"); 2076 2077 if (g_Session.StartupInfo.uSessionID == UINT32_MAX) 1194 2078 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No session ID specified"); 1195 2079 … … 1199 2083 strlen(g_szLogFile) ? g_szLogFile : "<None>", rc); 1200 2084 1201 RTEXITCODE rcExit = gstcntlSessionWorker( );2085 RTEXITCODE rcExit = gstcntlSessionWorker(&g_Session); 1202 2086 1203 2087 VBoxServiceLogDestroy(); … … 1205 2089 } 1206 2090 1207 static int gstcntlSessionForkShutdown(uint32_t uClientId, uint32_t cParms) 1208 { 1209 VBoxServiceVerbose(0, "Session %RU32 is about to shutdown ...\n", g_uSessionID); 2091 static int gstcntlSessionForkShutdown(PVBOXSERVICECTRLSESSION pSession) 2092 { 2093 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 2094 2095 VBoxServiceVerbose(0, "Session %RU32 is about to shutdown ...\n", 2096 pSession->StartupInfo.uSessionID); 1210 2097 1211 2098 /* Close all left guest files. */ 1212 2099 PVBOXSERVICECTRLFILE pFile; 1213 pFile = RTListGetFirst(& g_lstSessionFiles, VBOXSERVICECTRLFILE, Node);2100 pFile = RTListGetFirst(&pSession->lstFiles, VBOXSERVICECTRLFILE, Node); 1214 2101 while (pFile) 1215 2102 { 1216 2103 PVBOXSERVICECTRLFILE pNext = RTListNodeGetNext(&pFile->Node, VBOXSERVICECTRLFILE, Node); 1217 bool fLast = RTListNodeIsLast(& g_lstSessionFiles, &pFile->Node);2104 bool fLast = RTListNodeIsLast(&pSession->lstFiles, &pFile->Node); 1218 2105 1219 2106 int rc2 = gstcntlSessionFileDestroy(pFile); … … 1231 2118 } 1232 2119 1233 AssertMsg(RTListIsEmpty(& g_lstSessionFiles),2120 AssertMsg(RTListIsEmpty(&pSession->lstFiles), 1234 2121 ("Guest file list still contains entries when it should not\n")); 1235 2122 -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlThread.cpp
r44863 r44963 43 43 using namespace guestControl; 44 44 45 /* Internal functions. */ 46 static int gstcntlProcessRequestCancel(PVBOXSERVICECTRLREQUEST pThread); 45 /******************************************************************************* 46 * Internal Functions * 47 *******************************************************************************/ 48 static int gstcntlProcessAssignPID(PVBOXSERVICECTRLTHREAD pThread, uint32_t uPID); 49 static int gstcntlProcessRequestCancel(PVBOXSERVICECTRLREQUEST pThread); 50 static int gstcntlProcessSetupPipe(const char *pszHowTo, int fd, PRTHANDLE ph, PRTHANDLE *pph, PRTPIPE phPipe); 47 51 48 52 /** … … 220 224 if (RT_SUCCESS(rc)) 221 225 { 222 rc = GstCntlProcessPerform(pThread ->uPID, pRequest);226 rc = GstCntlProcessPerform(pThread, pRequest); 223 227 if (RT_FAILURE(rc)) 224 228 VBoxServiceVerbose(3, "[PID %u]: Sending quit request failed with rc=%Rrc\n", … … 228 232 } 229 233 return rc; 234 } 235 236 237 /** 238 * Releases (unlocks) a previously locked guest process. 239 * 240 * @param pThread Thread to unlock. 241 */ 242 void GstCntlProcessRelease(const PVBOXSERVICECTRLTHREAD pThread) 243 { 244 AssertPtr(pThread); 245 246 int rc = RTCritSectLeave(&pThread->CritSect); 247 AssertRC(rc); 230 248 } 231 249 … … 614 632 * the first (stale) entry will be found and we get really weird results! 615 633 */ 616 rc = GstCntlAssignPID(pThread, hProcess);634 rc = gstcntlProcessAssignPID(pThread, hProcess); 617 635 if (RT_FAILURE(rc)) 618 636 { … … 1092 1110 * should service. 1093 1111 */ 1094 int GstcntlProcessSetupPipe(const char *pszHowTo, int fd,1095 PRTHANDLE ph, PRTHANDLE *pph, PRTPIPE phPipe)1112 static int gstcntlProcessSetupPipe(const char *pszHowTo, int fd, 1113 PRTHANDLE ph, PRTHANDLE *pph, PRTPIPE phPipe) 1096 1114 { 1097 1115 AssertPtrReturn(ph, VERR_INVALID_POINTER); … … 1319 1337 1320 1338 1339 /** 1340 * Assigns a valid PID to a guest control thread and also checks if there already was 1341 * another (stale) guest process which was using that PID before and destroys it. 1342 * 1343 * @return IPRT status code. 1344 * @param pThread Thread to assign PID to. 1345 * @param uPID PID to assign to the specified guest control execution thread. 1346 */ 1347 int gstcntlProcessAssignPID(PVBOXSERVICECTRLTHREAD pThread, uint32_t uPID) 1348 { 1349 AssertPtrReturn(pThread, VERR_INVALID_POINTER); 1350 AssertReturn(uPID, VERR_INVALID_PARAMETER); 1351 1352 AssertPtr(pThread->pSession); 1353 int rc = RTCritSectEnter(&pThread->pSession->csControlThreads); 1354 if (RT_SUCCESS(rc)) 1355 { 1356 /* Search old threads using the desired PID and shut them down completely -- it's 1357 * not used anymore. */ 1358 PVBOXSERVICECTRLTHREAD pThreadCur; 1359 bool fTryAgain = false; 1360 do 1361 { 1362 RTListForEach(&pThread->pSession->lstControlThreadsActive, pThreadCur, VBOXSERVICECTRLTHREAD, Node) 1363 { 1364 if (pThreadCur->uPID == uPID) 1365 { 1366 Assert(pThreadCur != pThread); /* can't happen */ 1367 uint32_t uTriedPID = uPID; 1368 uPID += 391939; 1369 VBoxServiceVerbose(2, "PID %RU32 was used before, trying again with %u ...\n", 1370 uTriedPID, uPID); 1371 fTryAgain = true; 1372 break; 1373 } 1374 } 1375 } while (fTryAgain); 1376 1377 /* Assign PID to current thread. */ 1378 pThread->uPID = uPID; 1379 1380 rc = RTCritSectLeave(&pThread->pSession->csControlThreads); 1381 AssertRC(rc); 1382 } 1383 1384 return rc; 1385 } 1386 1387 1321 1388 void gstcntlProcessFreeArgv(char **papszArgv) 1322 1389 { … … 1491 1558 pThread, pThread->pszCmd); 1492 1559 1493 int rc = GstCntlListSet(VBOXSERVICECTRLTHREADLIST_RUNNING, pThread); 1560 int rc = GstCntlSessionListSet(pThread->pSession, 1561 VBOXSERVICECTRLTHREADLIST_RUNNING, pThread); 1494 1562 AssertRC(rc); 1495 1563 … … 1528 1596 RTHANDLE hStdIn; 1529 1597 PRTHANDLE phStdIn; 1530 rc = GstcntlProcessSetupPipe("|", 0 /*STDIN_FILENO*/,1598 rc = gstcntlProcessSetupPipe("|", 0 /*STDIN_FILENO*/, 1531 1599 &hStdIn, &phStdIn, &pThread->pipeStdInW); 1532 1600 if (RT_SUCCESS(rc)) … … 1535 1603 PRTHANDLE phStdOut; 1536 1604 RTPIPE pipeStdOutR; 1537 rc = GstcntlProcessSetupPipe( (pThread->uFlags & EXECUTEPROCESSFLAG_WAIT_STDOUT)1605 rc = gstcntlProcessSetupPipe( (pThread->uFlags & EXECUTEPROCESSFLAG_WAIT_STDOUT) 1538 1606 ? "|" : "/dev/null", 1539 1607 1 /*STDOUT_FILENO*/, … … 1544 1612 PRTHANDLE phStdErr; 1545 1613 RTPIPE pipeStdErrR; 1546 rc = GstcntlProcessSetupPipe( (pThread->uFlags & EXECUTEPROCESSFLAG_WAIT_STDERR)1614 rc = gstcntlProcessSetupPipe( (pThread->uFlags & EXECUTEPROCESSFLAG_WAIT_STDERR) 1547 1615 ? "|" : "/dev/null", 1548 1616 2 /*STDERR_FILENO*/, … … 1662 1730 1663 1731 /* Move thread to stopped thread list. */ 1664 int rc2 = GstCntlListSet(VBOXSERVICECTRLTHREADLIST_STOPPED, pThread); 1732 int rc2 = GstCntlSessionListSet(pThread->pSession, 1733 VBOXSERVICECTRLTHREADLIST_STOPPED, pThread); 1665 1734 AssertRC(rc2); 1666 1735 … … 1785 1854 * 1786 1855 * @return IPRT status code. 1787 * @param uPID PID of guest process to perform a request to.1856 * @param pProcess Guest process to perform operation on. 1788 1857 * @param pRequest Pointer to request to perform. 1789 1858 */ 1790 int GstCntlProcessPerform(uint32_t uPID, PVBOXSERVICECTRLREQUEST pRequest) 1791 { 1859 int GstCntlProcessPerform(PVBOXSERVICECTRLTHREAD pProcess, 1860 PVBOXSERVICECTRLREQUEST pRequest) 1861 { 1862 AssertPtrReturn(pProcess, VERR_INVALID_POINTER); 1792 1863 AssertPtrReturn(pRequest, VERR_INVALID_POINTER); 1793 1864 AssertReturn(pRequest->enmType > VBOXSERVICECTRLREQUEST_UNKNOWN, VERR_INVALID_PARAMETER); … … 1795 1866 1796 1867 int rc = VINF_SUCCESS; 1797 PVBOXSERVICECTRLTHREAD pThread = GstCntlLockThread(uPID); 1798 if (pThread) 1799 { 1800 if (ASMAtomicReadBool(&pThread->fShutdown)) 1801 { 1802 rc = VERR_CANCELLED; 1803 } 1804 else 1805 { 1806 /* Set request structure pointer. */ 1807 pThread->pRequest = pRequest; 1808 1809 /** @todo To speed up simultaneous guest process handling we could add a worker threads 1810 * or queue in order to wait for the request to happen. Later. */ 1811 /* Wake up guest thrad by sending a wakeup byte to the notification pipe so 1812 * that RTPoll unblocks (returns) and we then can do our requested operation. */ 1813 Assert(pThread->hNotificationPipeW != NIL_RTPIPE); 1814 size_t cbWritten; 1815 if (RT_SUCCESS(rc)) 1816 rc = RTPipeWrite(pThread->hNotificationPipeW, "i", 1, &cbWritten); 1817 1818 if ( RT_SUCCESS(rc) 1819 && cbWritten) 1820 { 1821 VBoxServiceVerbose(3, "[PID %u]: Waiting for response on enmType=%u, pvData=0x%p, cbData=%u\n", 1822 uPID, pRequest->enmType, pRequest->pvData, pRequest->cbData); 1823 1824 rc = GstCntlProcessRequestWait(pRequest); 1825 } 1826 } 1827 1828 GstCntlUnlockThread(pThread); 1829 } 1830 else /* PID not found! */ 1831 rc = VERR_NOT_FOUND; 1868 1869 if (ASMAtomicReadBool(&pProcess->fShutdown)) 1870 { 1871 rc = VERR_CANCELLED; 1872 } 1873 else 1874 { 1875 /* Set request structure pointer. */ 1876 pProcess->pRequest = pRequest; 1877 1878 /** @todo To speed up simultaneous guest process handling we could add a worker threads 1879 * or queue in order to wait for the request to happen. Later. */ 1880 /* Wake up guest thrad by sending a wakeup byte to the notification pipe so 1881 * that RTPoll unblocks (returns) and we then can do our requested operation. */ 1882 Assert(pProcess->hNotificationPipeW != NIL_RTPIPE); 1883 size_t cbWritten; 1884 if (RT_SUCCESS(rc)) 1885 rc = RTPipeWrite(pProcess->hNotificationPipeW, "i", 1, &cbWritten); 1886 1887 if ( RT_SUCCESS(rc) 1888 && cbWritten) 1889 { 1890 VBoxServiceVerbose(3, "[PID %u]: Waiting for response on enmType=%u, pvData=0x%p, cbData=%u\n", 1891 pProcess->uPID, pRequest->enmType, pRequest->pvData, pRequest->cbData); 1892 1893 rc = GstCntlProcessRequestWait(pRequest); 1894 } 1895 } 1832 1896 1833 1897 VBoxServiceVerbose(3, "[PID %u]: Performed enmType=%u, uCID=%u, pvData=0x%p, cbData=%u, rc=%Rrc\n", 1834 uPID, pRequest->enmType, pRequest->uCID, pRequest->pvData, pRequest->cbData, rc);1898 pProcess->uPID, pRequest->enmType, pRequest->uCID, pRequest->pvData, pRequest->cbData, rc); 1835 1899 return rc; 1836 1900 }
Note:
See TracChangeset
for help on using the changeset viewer.