VirtualBox

Changeset 44963 in vbox for trunk/src/VBox/Additions


Ignore:
Timestamp:
Mar 8, 2013 2:44:06 PM (12 years ago)
Author:
vboxsync
Message:

VBoxService/GuestCtrl: More code (revamp) for dedicated guest session handling. Untested, work in progress.

Location:
trunk/src/VBox/Additions/common/VBoxService
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp

    r44935 r44963  
    5353 *  the maximum number of processes is unlimited. */
    5454static 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.  */
     58RTLISTANCHOR                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. */
     64VBOXSERVICECTRLSESSION      g_Session;
    6765
    6866/*******************************************************************************
     
    7169static int  gstcntlHandleSessionOpen(PVBGLR3GUESTCTRLHOSTCTX pHostCtx);
    7270static 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);
    7971static void VBoxServiceControlShutdown(void);
    80 static int  vboxServiceControlProcessCloseAll(void);
    81 static int  gstcntlStartAllowed(bool *pbAllowed);
    82 
    83 #ifdef DEBUG
    84 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 #endif
    11472
    11573
     
    159117                                  &g_uControlIntervalMS, 1, UINT32_MAX - 1);
    160118#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    }
    161124    else if (!strcmp(argv[*pi], "--control-dump-stderr"))
    162125    {
    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;
    169127        rc = 0; /* Flag this command as parsed. */
    170128    }
     
    197155
    198156        /* 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);
    206158    }
    207159    else
     
    275227                /* Close all opened guest sessions -- all context IDs, sessions etc.
    276228                 * are now invalid. */
    277                 rc2 = vboxServiceControlProcessCloseAll();
     229                rc2 = GstCntlSessionCloseAll(&g_Session);
    278230                AssertRC(rc2);
    279231            }
     
    293245                    break;
    294246
    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 
    316247                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);
    319250                    break;
    320251            }
     
    339270
    340271    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 input
    367          * parameter to retrieve the stuff from the host. On output this then
    368          * 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 DEBUG
    397                                proc.szPassword,
    398 #else
    399                                "XXX", /* Never show passwords in release mode. */
    400 #endif
    401                                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                 else
    416                     rc = VERR_MAX_PROCS_REACHED; /* Maximum number of processes reached. */
    417             }
    418         }
    419     }
    420     else
    421         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 command
    430          *       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 becoming
    503  *                                  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                                           fPendingClose
    634                                           ? VBOXSERVICECTRLREQUEST_PROC_STDIN_EOF
    635                                           : 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 its
    655  * 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     else
    692     {
    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         else
    714         {
    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 status
    724      * 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 object
    739      *       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 DEBUG
    776             if (   g_fControlDumpStdErr
    777                 && 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_fControlDumpStdOut
    786                      && (   uHandleID == OUTPUT_HANDLE_ID_STDOUT
    787                          || 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 #endif
    797             /** Note: Don't convert/touch/modify/whatever the output data here! This might be binary
    798              *        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 object
    802              *       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         else
    813             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);
    819272    return rc;
    820273}
     
    840293                           pHostCtx->uClientID, pHostCtx->uProtocol);
    841294
    842         rc = GstCntlSessionOpen(&ssInfo, NULL /* Node */);
     295        rc = GstCntlSessionThreadOpen(&g_lstControlSessionThreads,
     296                                      &ssInfo, NULL /* Session */);
    843297    }
    844298
     
    869323        rc = VERR_NOT_FOUND;
    870324
    871         PVBOXSERVICECTRLSESSION pSession;
    872         RTListForEach(&g_lstControlSessions, pSession, VBOXSERVICECTRLSESSION, Node)
     325        PVBOXSERVICECTRLSESSIONTHREAD pSession;
     326        RTListForEach(&g_lstControlSessionThreads, pSession, VBOXSERVICECTRLSESSIONTHREAD, Node)
    873327        {
    874328            if (pSession->StartupInfo.uSessionID == uSessionID)
    875329            {
    876                 rc = GstCntlSessionClose(pSession, uFlags);
     330                rc = GstCntlSessionThreadClose(pSession, uFlags);
    877331                break;
    878332            }
     
    923377
    924378/**
    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             else
    955                 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 /**
    1025379 * Destroys all guest process threads which are still active.
    1026380 */
     
    1029383    VBoxServiceVerbose(2, "Shutting down ...\n");
    1030384
    1031     int rc2 = vboxServiceControlProcessCloseAll();
    1032     AssertRC(rc2);
    1033 
    1034     /* Destroy critical section. */
    1035     RTCritSectDelete(&g_csControlThreads);
     385    /* int GstCntlSessionDestroy(PVBOXSERVICECTRLSESSION pSession) */
    1036386
    1037387    VBoxServiceVerbose(2, "Shutting down complete\n");
     
    1056406        g_hControlEvent = NIL_RTSEMEVENTMULTI;
    1057407    }
    1058 }
    1059 
    1060 
    1061 /**
    1062  * Determines whether starting a new guest process according to the
    1063  * 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 process
    1067  *                              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 checking
    1078          * 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 unlocked
    1113  * 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 was
    1161  * 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's
    1176          * not used anymore. */
    1177         PVBOXSERVICECTRLTHREAD pThreadCur;
    1178         bool fTryAgain = false;
    1179         do
    1180         {
    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;
    1204408}
    1205409
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.h

    r44935 r44963  
    123123    uint32_t uTimeoutMS;
    124124} VBOXSERVICECTRLREQDATA_WAIT_FOR, *PVBOXSERVICECTRLREQDATA_WAIT_FOR;
     125
     126/**
     127 * Structure for one (opened) guest file.
     128 */
     129typedef 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. */
     148typedef VBOXSERVICECTRLFILE *PVBOXSERVICECTRLFILE;
     149
     150typedef 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. */
     167typedef VBOXSERVICECTRLSESSIONSTARTUPINFO *PVBOXSERVICECTRLSESSIONSTARTUPINFO;
     168
     169/**
     170 * Structure for a guest session thread to
     171 * observe the forked session instance.
     172 */
     173typedef 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. */
     215typedef 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 */
     234typedef 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. */
     254typedef VBOXSERVICECTRLSESSION *PVBOXSERVICECTRLSESSION;
    125255
    126256/**
     
    175305    /** The worker thread. */
    176306    RTTHREAD                        Thread;
     307    /** The session this guest process
     308     *  is bound to. */
     309    PVBOXSERVICECTRLSESSION         pSession;
    177310    /** Shutdown indicator; will be set when the thread
    178311      * needs (or is asked) to shutdown. */
     
    219352typedef VBOXSERVICECTRLTHREAD *PVBOXSERVICECTRLTHREAD;
    220353
    221 /**
    222  * Structure for one (opened) guest file.
    223  */
    224 typedef struct VBOXSERVICECTRLFILE
    225 {
    226     /** Pointer to list archor of following
    227      *  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 VBOXSERVICECTRLSESSIONSTARTUPINFO
    246 {
    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 VBOXSERVICECTRLSESSION
    268 {
    269     /** Node to global guest control session list. */
    270     /** @todo Use a map later? */
    271     RTLISTNODE                      Node;
    272     /** The sessions's startup info. */
    273     VBOXSERVICECTRLSESSIONSTARTUPINFO
    274                                     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 thread
    282       * 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 StdPipe
    295     {
    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 #endif
    307 } VBOXSERVICECTRLSESSION;
    308 /** Pointer to thread data. */
    309 typedef VBOXSERVICECTRLSESSION *PVBOXSERVICECTRLSESSION;
    310 
    311354RT_C_DECLS_BEGIN
    312355
     
    321364 */
    322365
    323 /* Guest session handling. */
    324 extern int                      GstCntlSessionOpen(const PVBOXSERVICECTRLSESSIONSTARTUPINFO pSessionStartupInfo, PRTLISTNODE pNode);
    325 extern int                      GstCntlSessionClose(PVBOXSERVICECTRLSESSION pSession, uint32_t uFlags);
    326 extern int                      GstCntlSessionTerminate(PVBOXSERVICECTRLSESSION pSession);
     366/* Guest session thread handling. */
     367extern int                      GstCntlSessionThreadOpen(PRTLISTANCHOR pList, const PVBOXSERVICECTRLSESSIONSTARTUPINFO pSessionStartupInfo, PVBOXSERVICECTRLSESSIONTHREAD *ppSessionThread);
     368extern int                      GstCntlSessionThreadClose(PVBOXSERVICECTRLSESSIONTHREAD pSession, uint32_t uFlags);
     369extern int                      GstCntlSessionThreadTerminate(PVBOXSERVICECTRLSESSIONTHREAD pSession);
    327370extern RTEXITCODE               VBoxServiceControlSessionForkInit(int argc, char **argv);
    328371
     372/* asdf */
     373extern PVBOXSERVICECTRLTHREAD   GstCntlSessionAcquireProcess(PVBOXSERVICECTRLSESSION pSession, uint32_t uPID);
     374extern int                      GstCntlSessionCloseAll(PVBOXSERVICECTRLSESSION pSession);
     375extern int                      GstCntlSessionDestroy(PVBOXSERVICECTRLSESSION pSession);
     376extern int                      GstCntlSessionHandler(PVBOXSERVICECTRLSESSION pSession, uint32_t uMsg, PVBGLR3GUESTCTRLHOSTCTX pHostCtx, void *pvScratchBuf, size_t cbScratchBuf, volatile bool *pfShutdown);
     377extern int                      GstCntlSessionListSet(PVBOXSERVICECTRLSESSION pSession, VBOXSERVICECTRLTHREADLISTTYPE enmList, PVBOXSERVICECTRLTHREAD pThread);
     378extern int                      GstCntlSessionProcessStartAllowed(const PVBOXSERVICECTRLSESSION pSession, bool *pbAllowed);
     379extern int                      GstCntlSessionReapThreads(PVBOXSERVICECTRLSESSION pSession);
     380
    329381/* Guest control main thread functions. */
    330 extern int                      GstCntlAssignPID(PVBOXSERVICECTRLTHREAD pThread, uint32_t uPID);
    331382extern int                      GstCntlListSet(VBOXSERVICECTRLTHREADLISTTYPE enmList, PVBOXSERVICECTRLTHREAD pThread);
    332 extern PVBOXSERVICECTRLTHREAD   GstCntlLockThread(uint32_t uPID);
    333 extern void                     GstCntlUnlockThread(const PVBOXSERVICECTRLTHREAD pThread);
    334383extern int                      GstCntlSetInactive(PVBOXSERVICECTRLTHREAD pThread);
    335384/* Per-thread guest process functions. */
    336 extern int                      GstcntlProcessSetupPipe(const char *pszHowTo, int fd, PRTHANDLE ph, PRTHANDLE *pph, PRTPIPE phPipe);
     385extern int                      GstCntlProcessPerform(PVBOXSERVICECTRLTHREAD pProcess, PVBOXSERVICECTRLREQUEST pRequest);
    337386extern int                      GstCntlProcessStart(uint32_t uContext, PVBOXSERVICECTRLPROCESS pProcess);
    338 extern int                      GstCntlProcessPerform(uint32_t uPID, PVBOXSERVICECTRLREQUEST pRequest);
    339387extern int                      GstCntlProcessStop(const PVBOXSERVICECTRLTHREAD pThread);
     388extern void                     GstCntlProcessRelease(const PVBOXSERVICECTRLTHREAD pThread);
    340389extern int                      GstCntlProcessWait(const PVBOXSERVICECTRLTHREAD pThread, RTMSINTERVAL msTimeout, int *prc);
    341390extern int                      GstCntlProcessFree(PVBOXSERVICECTRLTHREAD pThread);
    342 /* Request handling. */
     391/* Process request handling. */
    343392extern int                      GstCntlProcessRequestAlloc(PVBOXSERVICECTRLREQUEST *ppReq, VBOXSERVICECTRLREQUESTTYPE enmType);
    344393extern int                      GstCntlProcessRequestAllocEx(PVBOXSERVICECTRLREQUEST *ppReq, VBOXSERVICECTRLREQUESTTYPE  enmType, void *pvData, size_t cbData, uint32_t uCID);
    345394extern void                     GstCntlProcessRequestFree(PVBOXSERVICECTRLREQUEST pReq);
    346 /******************************************************************************
    347  * Guest file command handling.                                               *
    348  *****************************************************************************/
     395/* Per-session functions. */
    349396extern int gstcntlHandleFileOpen(uint32_t idClient, uint32_t cParms);
    350397extern int gstcntlHandleFileClose(uint32_t idClient, uint32_t cParms);
     
    355402extern int gstcntlHandleFileSeek(uint32_t idClient, uint32_t cParms);
    356403extern int gstcntlHandleFileTell(uint32_t idClient, uint32_t cParms);
     404extern int                      GstCntlSessionHandleProcExec(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLHOSTCTX pHostCtx);
     405extern int                      GstCntlSessionHandleProcInput(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLHOSTCTX pHostCtx, void *pvScratchBuf, size_t cbScratchBuf);
     406extern int                      GstCntlSessionHandleProcOutput(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLHOSTCTX pHostCtx);
     407extern int                      GstCntlSessionHandleProcTerminate(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLHOSTCTX pHostCtx);
     408extern int                      GstCntlSessionHandleProcWaitFor(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLHOSTCTX pHostCtx);
    357409
    358410RT_C_DECLS_END
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlSession.cpp

    r44935 r44963  
    4040using namespace guestControl;
    4141
    42 /** List of guest control sessions (VBOXSERVICECTRLSESSION). */
    43 extern RTLISTANCHOR         g_lstControlSessions;
     42/*******************************************************************************
     43*   Externals                                                                  *
     44*******************************************************************************/
     45extern RTLISTANCHOR                g_lstControlSessionThreads;
     46extern VBOXSERVICECTRLSESSION      g_Session;
     47
    4448extern int                  VBoxServiceLogCreate(const char *pszLogFile);
    4549extern void                 VBoxServiceLogDestroy(void);
     
    4953*******************************************************************************/
    5054static 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);
     55static int                  gstcntlSessionForkShutdown(PVBOXSERVICECTRLSESSION pSession);
     56static PVBOXSERVICECTRLFILE gstcntlSessionGetFile(const PVBOXSERVICECTRLSESSION pSession, uint32_t uHandle);
     57static 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);
     58static int                  gstcntlSessionHandleFileOpen(PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLHOSTCTX pHostCtx);
     59static int                  gstcntlSessionHandleFileClose(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLHOSTCTX pHostCtx);
     60static int                  gstcntlSessionHandleFileRead(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLHOSTCTX pHostCtx);
     61static int                  gstcntlSessionHandleFileWrite(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLHOSTCTX pHostCtx, void *pvScratchBuf, size_t cbScratchBuf);
     62static int                  gstcntlSessionHandleFileSeek(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLHOSTCTX pHostCtx);
     63static int                  gstcntlSessionHandleFileTell(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLHOSTCTX pHostCtx);
     64static int                  gstcntlSessionSetInput(const PVBOXSERVICECTRLSESSION pSession, uint32_t uPID, uint32_t uCID, bool fPendingClose, void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten);
    5965static 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;
    6766
    6867/** Generic option indices for session fork arguments. */
     
    9392
    9493
    95 static PVBOXSERVICECTRLFILE gstcntlSessionGetFile(uint32_t uHandle)
    96 {
     94static PVBOXSERVICECTRLFILE gstcntlSessionGetFile(const PVBOXSERVICECTRLSESSION pSession,
     95                                                  uint32_t uHandle)
     96{
     97    AssertPtrReturn(pSession, NULL);
     98
    9799    PVBOXSERVICECTRLFILE pFileCur = NULL;
    98100    /** @todo Use a map later! */
    99     RTListForEach(&g_lstSessionFiles, pFileCur, VBOXSERVICECTRLFILE, Node)
     101    RTListForEach(&pSession->lstFiles, pFileCur, VBOXSERVICECTRLFILE, Node)
    100102    {
    101103        if (pFileCur->uHandle == uHandle)
     
    107109
    108110
    109 static int gstcntlSessionHandleFileOpen(uint32_t uClientId, uint32_t cParms)
    110 {
     111#ifdef DEBUG
     112static 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
     144static int gstcntlSessionHandleFileOpen(PVBOXSERVICECTRLSESSION pSession,
     145                                        PVBGLR3GUESTCTRLHOSTCTX pHostCtx)
     146{
     147    AssertPtrReturn(pSession, VERR_INVALID_POINTER);
     148    AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
     149
    111150    char szFile[RTPATH_MAX];
    112151    char szOpenMode[64];
     
    116155
    117156    uint32_t uHandle = 0;
    118     VBGLR3GUESTCTRLHOSTCTX ctx = { uClientId, cParms };
    119     int rc = VbglR3GuestCtrlFileGetOpen(&ctx,
     157    int rc = VbglR3GuestCtrlFileGetOpen(pHostCtx,
    120158                                        /* File to open. */
    121159                                        szFile, sizeof(szFile),
     
    156194            if (RT_SUCCESS(rc))
    157195            {
    158                 uHandle = VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(ctx.uContextID);
     196                uHandle = VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pHostCtx->uContextID);
    159197                pFile->uHandle = uHandle;
    160                 /* rc = */ RTListAppend(&g_lstSessionFiles, &pFile->Node);
     198                /* rc = */ RTListAppend(&pSession->lstFiles, &pFile->Node);
    161199
    162200                VBoxServiceVerbose(3, "[File %s]: Opened (ID=%RU32)\n",
     
    172210        /* Report back in any case. */
    173211        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));
    176214        if (RT_FAILURE(rc2))
    177215            VBoxServiceError("[File %s]: Failed to report file open status, rc=%Rrc\n",
     
    185223
    186224
    187 static int gstcntlSessionHandleFileClose(uint32_t uClientId, uint32_t cParms)
    188 {
     225static int gstcntlSessionHandleFileClose(const PVBOXSERVICECTRLSESSION pSession,
     226                                         PVBGLR3GUESTCTRLHOSTCTX pHostCtx)
     227{
     228    AssertPtrReturn(pSession, VERR_INVALID_POINTER);
     229    AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
     230
    189231    uint32_t uHandle;
    190232
    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);
    196237        if (pFile)
    197238        {
     
    203244        /* Report back in any case. */
    204245        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));
    207248        if (RT_FAILURE(rc2))
    208249            VBoxServiceError("Failed to report file close status, rc=%Rrc\n", rc2);
     
    214255
    215256
    216 static int gstcntlSessionHandleFileRead(uint32_t uClientId, uint32_t cParms,
     257static int gstcntlSessionHandleFileRead(const PVBOXSERVICECTRLSESSION pSession,
     258                                        PVBGLR3GUESTCTRLHOSTCTX pHostCtx,
    217259                                        void *pvScratchBuf, size_t cbScratchBuf)
    218260{
     261    AssertPtrReturn(pSession, VERR_INVALID_POINTER);
     262    AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
     263
    219264    uint32_t uHandle;
    220265    uint32_t cbToRead;
    221266
    222     VBGLR3GUESTCTRLHOSTCTX ctx = { uClientId, cParms };
    223     int rc = VbglR3GuestCtrlFileGetRead(&ctx, &uHandle, &cbToRead);
     267    int rc = VbglR3GuestCtrlFileGetRead(pHostCtx, &uHandle, &cbToRead);
    224268    if (RT_SUCCESS(rc))
    225269    {
     
    227271        size_t cbRead = 0;
    228272
    229         PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(uHandle);
     273        PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(pSession, uHandle);
    230274        if (pFile)
    231275        {
     
    250294        /* Report back in any case. */
    251295        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));
    254298        if (   cbToRead > cbScratchBuf
    255299            && pvDataRead)
     
    265309
    266310
    267 static int gstcntlSessionHandleFileReadAt(uint32_t uClientId, uint32_t cParms,
     311static int gstcntlSessionHandleFileReadAt(const PVBOXSERVICECTRLSESSION pSession,
     312                                          PVBGLR3GUESTCTRLHOSTCTX pHostCtx,
    268313                                          void *pvScratchBuf, size_t cbScratchBuf)
    269314{
     315    AssertPtrReturn(pSession, VERR_INVALID_POINTER);
     316    AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
     317
    270318    uint32_t uHandle;
    271319    uint32_t cbToRead; int64_t iOffset;
    272320
    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);
    275323    if (RT_SUCCESS(rc))
    276324    {
     
    278326        size_t cbRead = 0;
    279327
    280         PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(uHandle);
     328        PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(pSession, uHandle);
    281329        if (pFile)
    282330        {
     
    301349        /* Report back in any case. */
    302350        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));
    305353        if (   cbToRead > cbScratchBuf
    306354            && pvDataRead)
     
    316364
    317365
    318 static int gstcntlSessionHandleFileWrite(uint32_t uClientId, uint32_t cParms,
     366static int gstcntlSessionHandleFileWrite(const PVBOXSERVICECTRLSESSION pSession,
     367                                         PVBGLR3GUESTCTRLHOSTCTX pHostCtx,
    319368                                         void *pvScratchBuf, size_t cbScratchBuf)
    320369{
     370    AssertPtrReturn(pSession, VERR_INVALID_POINTER);
     371    AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
    321372    AssertPtrReturn(pvScratchBuf, VERR_INVALID_POINTER);
    322373    AssertPtrReturn(cbScratchBuf, VERR_INVALID_PARAMETER);
     
    325376    uint32_t cbToWrite;
    326377
    327     VBGLR3GUESTCTRLHOSTCTX ctx = { uClientId, cParms };
    328     int rc = VbglR3GuestCtrlFileGetWrite(&ctx, &uHandle,
     378    int rc = VbglR3GuestCtrlFileGetWrite(pHostCtx, &uHandle,
    329379                                         pvScratchBuf, cbScratchBuf,
    330380                                         &cbToWrite);
     
    332382    {
    333383        size_t cbWritten = 0;
    334         PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(uHandle);
     384        PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(pSession, uHandle);
    335385        if (pFile)
    336386        {
     
    342392        /* Report back in any case. */
    343393        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));
    346396        if (RT_FAILURE(rc2))
    347397            VBoxServiceError("Failed to report file write status, rc=%Rrc\n", rc2);
     
    353403
    354404
    355 static int gstcntlSessionHandleFileWriteAt(uint32_t uClientId, uint32_t cParms,
     405static int gstcntlSessionHandleFileWriteAt(const PVBOXSERVICECTRLSESSION pSession,
     406                                           PVBGLR3GUESTCTRLHOSTCTX pHostCtx,
    356407                                           void *pvScratchBuf, size_t cbScratchBuf)
    357408{
     409    AssertPtrReturn(pSession, VERR_INVALID_POINTER);
     410    AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
    358411    AssertPtrReturn(pvScratchBuf, VERR_INVALID_POINTER);
    359412    AssertPtrReturn(cbScratchBuf, VERR_INVALID_PARAMETER);
     
    362415    uint32_t cbToWrite; int64_t iOffset;
    363416
    364     VBGLR3GUESTCTRLHOSTCTX ctx = { uClientId, cParms };
    365     int rc = VbglR3GuestCtrlFileGetWriteAt(&ctx, &uHandle,
     417    int rc = VbglR3GuestCtrlFileGetWriteAt(pHostCtx, &uHandle,
    366418                                           pvScratchBuf, cbScratchBuf,
    367419                                           &cbToWrite, (uint64_t*)&iOffset);
     
    369421    {
    370422        size_t cbWritten = 0;
    371         PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(uHandle);
     423        PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(pSession, uHandle);
    372424        if (pFile)
    373425        {
     
    380432        /* Report back in any case. */
    381433        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));
    384436        if (RT_FAILURE(rc2))
    385437            VBoxServiceError("Failed to report file write status, rc=%Rrc\n", rc2);
     
    391443
    392444
    393 static int gstcntlSessionHandleFileSeek(uint32_t uClientId, uint32_t cParms)
    394 {
     445static int gstcntlSessionHandleFileSeek(const PVBOXSERVICECTRLSESSION pSession,
     446                                        PVBGLR3GUESTCTRLHOSTCTX pHostCtx)
     447{
     448    AssertPtrReturn(pSession, VERR_INVALID_POINTER);
     449    AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
     450
    395451    uint32_t uHandle;
    396452    uint32_t uSeekMethod;
     
    399455    uint64_t uOffsetActual = 0;
    400456
    401     VBGLR3GUESTCTRLHOSTCTX ctx = { uClientId, cParms };
    402     int rc = VbglR3GuestCtrlFileGetSeek(&ctx, &uHandle,
     457    int rc = VbglR3GuestCtrlFileGetSeek(pHostCtx, &uHandle,
    403458                                        &uSeekMethod, &uOffset);
    404459    if (RT_SUCCESS(rc))
    405460    {
    406         PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(uHandle);
     461        PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(pSession, uHandle);
    407462        if (pFile)
    408463        {
     
    436491        /* Report back in any case. */
    437492        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));
    440495        if (RT_FAILURE(rc2))
    441496            VBoxServiceError("Failed to report file seek status, rc=%Rrc\n", rc2);
     
    447502
    448503
    449 static int gstcntlSessionHandleFileTell(uint32_t uClientId, uint32_t cParms)
    450 {
     504static int gstcntlSessionHandleFileTell(const PVBOXSERVICECTRLSESSION pSession,
     505                                        PVBGLR3GUESTCTRLHOSTCTX pHostCtx)
     506{
     507    AssertPtrReturn(pSession, VERR_INVALID_POINTER);
     508    AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
     509
    451510    uint32_t uHandle;
    452511    uint64_t uOffsetActual = 0;
    453512
    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);
    459517        if (pFile)
    460518        {
     
    466524        /* Report back in any case. */
    467525        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));
    470528        if (RT_FAILURE(rc2))
    471529            VBoxServiceError("Failed to report file tell status, rc=%Rrc\n", rc2);
     
    473531            rc = rc2;
    474532    }
     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 */
     545int 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 */
     651int 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 */
     748int 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
     821int 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
     853int 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
     888int 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
    475975    return rc;
    476976}
     
    489989static DECLCALLBACK(int) gstcntlSessionThread(RTTHREAD ThreadSelf, void *pvUser)
    490990{
    491     PVBOXSERVICECTRLSESSION pSession = (PVBOXSERVICECTRLSESSION)pvUser;
     991    PVBOXSERVICECTRLSESSIONTHREAD pSession = (PVBOXSERVICECTRLSESSIONTHREAD)pvUser;
    492992    AssertPtrReturn(pSession, VERR_INVALID_POINTER);
    493993
     
    5321032
    5331033
    534 RTEXITCODE gstcntlSessionWorker(void)
    535 {
     1034RTEXITCODE gstcntlSessionWorker(PVBOXSERVICECTRLSESSION pSession)
     1035{
     1036    AssertPtrReturn(pSession, RTEXITCODE_SYNTAX);
     1037
    5361038    bool fSessionFilter = true;
    5371039
    5381040    VBoxServiceVerbose(0, "Hi, this is guest session ID=%RU32\n",
    539                        g_uSessionID);
     1041                       pSession->StartupInfo.uSessionID);
    5401042
    5411043    uint32_t uClientID;
     
    5441046    {
    5451047        /* 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);
    5471050
    5481051        rc = VbglR3GuestCtrlMsgSetFilter(uClientID, uFilterAdd, 0 /* Filter remove */);
     
    5581061            rc = VINF_SUCCESS;
    5591062        }
    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);
    5611068
    5621069    /* Allocate a scratch buffer for commands which also send
     
    5681075    if (RT_SUCCESS(rc))
    5691076    {
    570         RTListInit(&g_lstSessionFiles);
    5711077        pvScratchBuf = (uint8_t*)RTMemAlloc(cbScratchBuf);
    5721078        if (!pvScratchBuf)
     
    5781084        bool fShutdown = false;
    5791085
     1086        VBGLR3GUESTCTRLHOSTCTX ctxHost = { uClientID,
     1087                                           pSession->StartupInfo.uProtocol };
    5801088        for (;;)
    5811089        {
     
    5951103                VBoxServiceVerbose(3, "Msg=%RU32 (%RU32 parms) retrieved\n", uMsg, cParms);
    5961104
    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);
    6511107            }
    6521108
     
    6591115    }
    6601116
    661     VBoxServiceVerbose(0, "Session %RU32 ended\n", g_uSessionID);
     1117    VBoxServiceVerbose(0, "Session %RU32 ended\n", pSession->StartupInfo.uSessionID);
    6621118
    6631119    if (pvScratchBuf)
     
    6691125    VBoxServiceVerbose(3, "Session worker returned with rc=%Rrc\n", rc);
    6701126    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 */
     1138PVBOXSERVICECTRLTHREAD 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
     1167int 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
     1211int 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 */
     1238static 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
     1291int 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 */
     1326int 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 */
     1393int 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 */
     1442int 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 */
     1501int 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;
    6711539}
    6721540
     
    6781546 *
    6791547 * @return  IPRT status code.
     1548 * @param   pList                   Which list to use to store the session thread in.
    6801549 * @param   pSessionStartupInfo     Session startup info.
    681  * @param   pNode                   Returns newly created session node on success.
     1550 * @param   ppSessionThread         Returns newly created session thread on success.
    6821551 *                                  Optional.
    6831552 */
    684 int GstCntlSessionOpen(const PVBOXSERVICECTRLSESSIONSTARTUPINFO pSessionStartupInfo,
    685                        PRTLISTNODE pNode)
    686 {
     1553int GstCntlSessionThreadOpen(PRTLISTANCHOR pList,
     1554                             const PVBOXSERVICECTRLSESSIONSTARTUPINFO pSessionStartupInfo,
     1555                             PVBOXSERVICECTRLSESSIONTHREAD *ppSessionThread)
     1556{
     1557    AssertPtrReturn(pList, VERR_INVALID_POINTER);
    6871558    AssertPtrReturn(pSessionStartupInfo, VERR_INVALID_POINTER);
    688     /* pNode is optional. */
     1559    /* ppSessionThread is optional. */
    6891560
    6901561#ifdef DEBUG
    691     PVBOXSERVICECTRLSESSION pSessionCur;
     1562    PVBOXSERVICECTRLSESSIONTHREAD pSessionCur;
    6921563    /* Check for existing session in debug mode. Should never happen because of
    6931564     * Main consistency. */
    694     RTListForEach(&g_lstControlSessions, pSessionCur, VBOXSERVICECTRLSESSION, Node)
     1565    RTListForEach(pList, pSessionCur, VBOXSERVICECTRLSESSIONTHREAD, Node)
    6951566    {
    6961567        if (pSessionCur->StartupInfo.uSessionID == pSessionStartupInfo->uSessionID)
     
    7041575    int rc = VINF_SUCCESS;
    7051576
    706     PVBOXSERVICECTRLSESSION pSession = (PVBOXSERVICECTRLSESSION)RTMemAllocZ(sizeof(VBOXSERVICECTRLSESSION));
     1577    PVBOXSERVICECTRLSESSIONTHREAD pSession = (PVBOXSERVICECTRLSESSIONTHREAD)RTMemAllocZ(sizeof(VBOXSERVICECTRLSESSIONTHREAD));
    7071578    if (pSession)
    7081579    {
     
    9681839
    9691840                    /* Add session to list. */
    970                     /* rc = */ RTListAppend(&g_lstControlSessions, &pSession->Node);
    971                     if (pNode) /* Return node if wanted. */
    972                         pNode = &pSession->Node;
     1841                    /* rc = */ RTListAppend(pList, &pSession->Node);
     1842                    if (ppSessionThread) /* Return session if wanted. */
     1843                        *ppSessionThread = pSession;
    9731844                }
    9741845            }
     
    9961867 * @param   uFlags                  Closing flags.
    9971868 */
    998 int GstCntlSessionClose(PVBOXSERVICECTRLSESSION pSession, uint32_t uFlags)
     1869int GstCntlSessionThreadClose(PVBOXSERVICECTRLSESSIONTHREAD pSession, uint32_t uFlags)
    9991870{
    10001871    AssertPtrReturn(pSession, VERR_INVALID_POINTER);
     
    10121883        uint32_t cMsTimeout = 30 * 1000; /* 30 seconds. */
    10131884
    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",
    10151886                           pSession->StartupInfo.uSessionID, cMsTimeout);
    10161887
     
    10191890        if (RT_FAILURE(rc))
    10201891        {
    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);
    10221894        }
    10231895        else
    10241896        {
    10251897            fAlive = false;
    1026             VBoxServiceVerbose(3, "Session ID=%RU32 thread ended with rc=%Rrc\n",
     1898            VBoxServiceVerbose(3, "Session thread ID=%RU32 ended with rc=%Rrc\n",
    10271899                               pSession->StartupInfo.uSessionID, rcThread);
    10281900        }
     
    10531925            RTThreadSleep(100); /* Wait a bit. */
    10541926        }
    1055     #endif
    1056 
     1927#endif
    10571928        if (fAlive)
    10581929        {
    1059             VBoxServiceVerbose(3, "Session ID=%RU32 still alive, killing ...\n",
     1930            VBoxServiceVerbose(3, "Session thread ID=%RU32 still alive, killing ...\n",
    10601931                               pSession->StartupInfo.uSessionID);
    1061             int rc2 = GstCntlSessionTerminate(pSession);
     1932            int rc2 = GstCntlSessionThreadTerminate(pSession);
    10621933            if (RT_SUCCESS(rc))
    10631934                rc = rc2;
     
    10791950
    10801951/**
    1081  * Close all formerly opened guest sessions.
     1952 * Close all formerly opened guest session threads.
    10821953 *
    10831954 * @return  IPRT status code.
     1955 * @param   pList                   Which list to close the session threads for.
    10841956 * @param   uFlags                  Closing flags.
    10851957 */
    1086 int GstCntlSessionCloseAll(uint32_t uFlags)
    1087 {
     1958int GstCntlSessionThreadCloseAll(PRTLISTANCHOR pList, uint32_t uFlags)
     1959{
     1960    AssertPtrReturn(pList, VERR_INVALID_POINTER);
     1961
    10881962    int rc = VINF_SUCCESS;
    10891963
    1090     PVBOXSERVICECTRLSESSION pSessionCur;
    1091     RTListForEach(&g_lstControlSessions, pSessionCur, VBOXSERVICECTRLSESSION, Node)
    1092     {
    1093         int rc2 = GstCntlSessionClose(pSessionCur, uFlags);
     1964    PVBOXSERVICECTRLSESSIONTHREAD pSessionCur;
     1965    RTListForEach(pList, pSessionCur, VBOXSERVICECTRLSESSIONTHREAD, Node)
     1966    {
     1967        int rc2 = GstCntlSessionThreadClose(pSessionCur, uFlags);
    10941968        if (RT_SUCCESS(rc))
    10951969        {
     
    11041978
    11051979/**
    1106  * Terminates a formerly opened guest session. Only
     1980 * Terminates a formerly opened guest session thread. Only
    11071981 * use this as a last action!
    11081982 *
     
    11101984 * @param   pSession                Guest session to terminate.
    11111985 */
    1112 int GstCntlSessionTerminate(PVBOXSERVICECTRLSESSION pSession)
    1113 {
    1114     AssertPtrReturn(pSession, VERR_INVALID_POINTER);
     1986int GstCntlSessionThreadTerminate(PVBOXSERVICECTRLSESSIONTHREAD pSession)
     1987{
     1988    AssertPtrReturn(pSession, VERR_INVALID_POINTER);
     1989
     1990    if (pSession->hProcess == NIL_RTPROCESS)
     1991        return VINF_SUCCESS; /* Nothing to terminate. */
    11151992
    11161993    int rc;
    1117 
    11181994    for (int i = 0; i < 3; i++)
    11191995    {
     
    11482024    int rc = VINF_SUCCESS;
    11492025
     2026    uint32_t uSessionFlags = VBOXSERVICECTRLSESSION_FLAG_FORK;
     2027
    11502028    while (   (ch = RTGetOpt(&GetState, &ValueUnion))
    11512029           && RT_SUCCESS(rc))
     
    11652043
    11662044            case VBOXSERVICESESSIONOPT_SESSION_ID:
    1167                 g_uSessionID = ValueUnion.u32;
     2045                g_Session.StartupInfo.uSessionID = ValueUnion.u32;
    11682046                break;
    11692047
    11702048            case VBOXSERVICESESSIONOPT_SESSION_PROTO:
    1171                 g_uSessionProto = ValueUnion.u32;
     2049                g_Session.StartupInfo.uProtocol = ValueUnion.u32;
    11722050                break;
    11732051
     
    11912069        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Initialization failed with rc=%Rrc", rc);
    11922070
    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)
    11942078        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No session ID specified");
    11952079
     
    11992083                              strlen(g_szLogFile) ? g_szLogFile : "<None>", rc);
    12002084
    1201     RTEXITCODE rcExit = gstcntlSessionWorker();
     2085    RTEXITCODE rcExit = gstcntlSessionWorker(&g_Session);
    12022086
    12032087    VBoxServiceLogDestroy();
     
    12052089}
    12062090
    1207 static int gstcntlSessionForkShutdown(uint32_t uClientId, uint32_t cParms)
    1208 {
    1209     VBoxServiceVerbose(0, "Session %RU32 is about to shutdown ...\n", g_uSessionID);
     2091static 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);
    12102097
    12112098    /* Close all left guest files. */
    12122099    PVBOXSERVICECTRLFILE pFile;
    1213     pFile = RTListGetFirst(&g_lstSessionFiles, VBOXSERVICECTRLFILE, Node);
     2100    pFile = RTListGetFirst(&pSession->lstFiles, VBOXSERVICECTRLFILE, Node);
    12142101    while (pFile)
    12152102    {
    12162103        PVBOXSERVICECTRLFILE pNext = RTListNodeGetNext(&pFile->Node, VBOXSERVICECTRLFILE, Node);
    1217         bool fLast = RTListNodeIsLast(&g_lstSessionFiles, &pFile->Node);
     2104        bool fLast = RTListNodeIsLast(&pSession->lstFiles, &pFile->Node);
    12182105
    12192106        int rc2 = gstcntlSessionFileDestroy(pFile);
     
    12312118    }
    12322119
    1233     AssertMsg(RTListIsEmpty(&g_lstSessionFiles),
     2120    AssertMsg(RTListIsEmpty(&pSession->lstFiles),
    12342121              ("Guest file list still contains entries when it should not\n"));
    12352122
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlThread.cpp

    r44863 r44963  
    4343using namespace guestControl;
    4444
    45 /* Internal functions. */
    46 static int gstcntlProcessRequestCancel(PVBOXSERVICECTRLREQUEST pThread);
     45/*******************************************************************************
     46*   Internal Functions                                                         *
     47*******************************************************************************/
     48static int                  gstcntlProcessAssignPID(PVBOXSERVICECTRLTHREAD pThread, uint32_t uPID);
     49static int                  gstcntlProcessRequestCancel(PVBOXSERVICECTRLREQUEST pThread);
     50static int                  gstcntlProcessSetupPipe(const char *pszHowTo, int fd, PRTHANDLE ph, PRTHANDLE *pph, PRTPIPE phPipe);
    4751
    4852/**
     
    220224    if (RT_SUCCESS(rc))
    221225    {
    222         rc = GstCntlProcessPerform(pThread->uPID, pRequest);
     226        rc = GstCntlProcessPerform(pThread, pRequest);
    223227        if (RT_FAILURE(rc))
    224228            VBoxServiceVerbose(3, "[PID %u]: Sending quit request failed with rc=%Rrc\n",
     
    228232    }
    229233    return rc;
     234}
     235
     236
     237/**
     238 * Releases (unlocks) a previously locked guest process.
     239 *
     240 * @param   pThread                 Thread to unlock.
     241 */
     242void GstCntlProcessRelease(const PVBOXSERVICECTRLTHREAD pThread)
     243{
     244    AssertPtr(pThread);
     245
     246    int rc = RTCritSectLeave(&pThread->CritSect);
     247    AssertRC(rc);
    230248}
    231249
     
    614632     * the first (stale) entry will be found and we get really weird results!
    615633     */
    616     rc = GstCntlAssignPID(pThread, hProcess);
     634    rc = gstcntlProcessAssignPID(pThread, hProcess);
    617635    if (RT_FAILURE(rc))
    618636    {
     
    10921110 *                              should service.
    10931111 */
    1094 int GstcntlProcessSetupPipe(const char *pszHowTo, int fd,
    1095                             PRTHANDLE ph, PRTHANDLE *pph, PRTPIPE phPipe)
     1112static int gstcntlProcessSetupPipe(const char *pszHowTo, int fd,
     1113                                   PRTHANDLE ph, PRTHANDLE *pph, PRTPIPE phPipe)
    10961114{
    10971115    AssertPtrReturn(ph, VERR_INVALID_POINTER);
     
    13191337
    13201338
     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 */
     1347int 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
    13211388void gstcntlProcessFreeArgv(char **papszArgv)
    13221389{
     
    14911558                       pThread, pThread->pszCmd);
    14921559
    1493     int rc = GstCntlListSet(VBOXSERVICECTRLTHREADLIST_RUNNING, pThread);
     1560    int rc = GstCntlSessionListSet(pThread->pSession,
     1561                                   VBOXSERVICECTRLTHREADLIST_RUNNING, pThread);
    14941562    AssertRC(rc);
    14951563
     
    15281596            RTHANDLE    hStdIn;
    15291597            PRTHANDLE   phStdIn;
    1530             rc = GstcntlProcessSetupPipe("|", 0 /*STDIN_FILENO*/,
     1598            rc = gstcntlProcessSetupPipe("|", 0 /*STDIN_FILENO*/,
    15311599                                         &hStdIn, &phStdIn, &pThread->pipeStdInW);
    15321600            if (RT_SUCCESS(rc))
     
    15351603                PRTHANDLE   phStdOut;
    15361604                RTPIPE      pipeStdOutR;
    1537                 rc = GstcntlProcessSetupPipe(  (pThread->uFlags & EXECUTEPROCESSFLAG_WAIT_STDOUT)
     1605                rc = gstcntlProcessSetupPipe(  (pThread->uFlags & EXECUTEPROCESSFLAG_WAIT_STDOUT)
    15381606                                             ? "|" : "/dev/null",
    15391607                                             1 /*STDOUT_FILENO*/,
     
    15441612                    PRTHANDLE   phStdErr;
    15451613                    RTPIPE      pipeStdErrR;
    1546                     rc = GstcntlProcessSetupPipe(  (pThread->uFlags & EXECUTEPROCESSFLAG_WAIT_STDERR)
     1614                    rc = gstcntlProcessSetupPipe(  (pThread->uFlags & EXECUTEPROCESSFLAG_WAIT_STDERR)
    15471615                                                 ? "|" : "/dev/null",
    15481616                                                 2 /*STDERR_FILENO*/,
     
    16621730
    16631731    /* Move thread to stopped thread list. */
    1664     int rc2 = GstCntlListSet(VBOXSERVICECTRLTHREADLIST_STOPPED, pThread);
     1732    int rc2 = GstCntlSessionListSet(pThread->pSession,
     1733                                    VBOXSERVICECTRLTHREADLIST_STOPPED, pThread);
    16651734    AssertRC(rc2);
    16661735
     
    17851854 *
    17861855 * @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.
    17881857 * @param   pRequest            Pointer to request  to perform.
    17891858 */
    1790 int GstCntlProcessPerform(uint32_t uPID, PVBOXSERVICECTRLREQUEST pRequest)
    1791 {
     1859int GstCntlProcessPerform(PVBOXSERVICECTRLTHREAD pProcess,
     1860                          PVBOXSERVICECTRLREQUEST pRequest)
     1861{
     1862    AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
    17921863    AssertPtrReturn(pRequest, VERR_INVALID_POINTER);
    17931864    AssertReturn(pRequest->enmType > VBOXSERVICECTRLREQUEST_UNKNOWN, VERR_INVALID_PARAMETER);
     
    17951866
    17961867    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    }
    18321896
    18331897    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);
    18351899    return rc;
    18361900}
Note: See TracChangeset for help on using the changeset viewer.

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