SessionState never unlocked

Discussion about using the VirtualBox API, Tutorials, Samples.

SessionState never unlocked

Postby mbono » 21. Apr 2022, 14:21

Hello,

I have used the VirtualBox COM interface for a while with VirtualBox 6.0. Now I am having troubles with 6.1.

The following code works well on 6.0.

* I start a VM in "headless"
* When the state is Running I stop it
* Then I wait until the session state is unlocked again
* I redo the previous steps 10 times.

simple_vbox_test.cpp
(6.25 KiB) Downloaded 7 times

Code: Select all   Expand viewCollapse view
#include "VirtualBox.h"

#include <chrono>
#include <string>
#include <thread>

#define SAFE_RELEASE(x)                                                                                                \
  if (x)                                                                                                               \
  {                                                                                                                    \
    x->Release();                                                                                                      \
    x = NULL;                                                                                                          \
  }

void printErrorInfo()
{
  IErrorInfo *errorInfo;
  HRESULT rc = GetErrorInfo(0, &errorInfo);
  if (FAILED(rc))
  {
    printf("Failed to get error info! rc = 0x%x\n", rc);
    return;
  }

  BSTR errorDescription = NULL;

  rc = errorInfo->GetDescription(&errorDescription);

  if (FAILED(rc) || !errorDescription)
  {
    printf("Error getting error description! rc = 0x%x\n", rc);
    return;
  }

  printf("Successfully retrieved error description: %S\n", errorDescription);
  SysFreeString(errorDescription);
  SAFE_RELEASE(errorInfo);
}

int testStartVM(IVirtualBox *virtualBox, const wchar_t *name, const wchar_t *sessionTypeName)
{
  HRESULT rc;

  /* Try to start a VM called "WinXP SP2". */
  IMachine *machine = NULL;
  BSTR machineName = SysAllocString(name);

  rc = virtualBox->FindMachine(machineName, &machine);

  if (FAILED(rc))
  {
    printErrorInfo();
  }
  else
  {
    ISession *session = NULL;
    IConsole *console = NULL;
    IProgress *progress = NULL;
    BSTR sessiontype = SysAllocString(sessionTypeName);
    BSTR guid;

    do
    {
      rc = machine->get_Id(&guid); /* Get the GUID of the machine. */
      if (!SUCCEEDED(rc))
      {
        printf("Error retrieving machine ID! rc = 0x%x\n", rc);
        printErrorInfo();
        break;
      }

      /* Create the session object. */
      rc = CoCreateInstance(CLSID_Session,        /* the VirtualBox base object */
                            NULL,                 /* no aggregation */
                            CLSCTX_INPROC_SERVER, /* the object lives in the current process */
                            IID_ISession,         /* IID of the interface */
                            (void **)&session);
      if (!SUCCEEDED(rc))
      {
        printf("Error creating Session instance! rc = 0x%x\n", rc);
        printErrorInfo();
        break;
      }

      /* Start a VM session using the delivered VBox GUI. */
      rc = machine->LaunchVMProcess(session, sessiontype, NULL, &progress);
      if (!SUCCEEDED(rc))
      {
        printf("Could not open remote session! rc = 0x%x\n", rc);
        printErrorInfo();
        break;
      }

      /* Wait until VM is running. */
      printf("Starting VM, please wait ...\n");
      rc = progress->WaitForCompletion(-1);
      if (!SUCCEEDED(rc))
      {
        printf("Progress wait for LaunchVMProcess completion fail! rc = 0x%x\n", rc);
        printErrorInfo();
        break;
      }

      /* Get console object. */
      session->get_Console(&console);

      /* Bring console window to front. */
      machine->ShowConsoleWindow(0);

      while (true)
      {
        MachineState state;
        rc = machine->get_State(&state);
        if (FAILED(rc))
        {
          printf("Faile to get machine state! rc = 0x%x\n", rc);
          printErrorInfo();
          break;
        }

        printf("Machine state == %d\n", state);
        if (state == MachineState_Running)
        {
          break;
        }
      }

      /* Power down the machine. */
      rc = console->PowerDown(&progress);
      if (!SUCCEEDED(rc))
      {
        printf("Console PowerDown fail! rc = 0x%x\n", rc);
        printErrorInfo();
        break;
      }

      /* Wait until VM is powered down. */
      printf("Powering off VM, please wait ...\n");
      rc = progress->WaitForCompletion(-1);
      if (!SUCCEEDED(rc))
      {
        printf("Progress wait for PowerDown fail! rc = 0x%x\n", rc);
        printErrorInfo();
        break;
      }

      /* Close the session. */
      rc = session->UnlockMachine();
      if (!SUCCEEDED(rc))
      {
        printf("Cannot unlock machine! rc = 0x%x\n", rc);
        printErrorInfo();
        break;
      }

    } while (0);

    SAFE_RELEASE(console);
    SAFE_RELEASE(progress);
    SAFE_RELEASE(session);
    SysFreeString(guid);
    SysFreeString(sessiontype);

    // wait for unlocked
    printf("Wait for machine unlocked ...\n");
    while (true)
    {
      SessionState sessionState;
      rc = machine->get_SessionState(&sessionState);
      if (FAILED(rc))
      {
        printf("Cannot get session state! rc = 0x%x\n", rc);
        printErrorInfo();
        break;
      }

      if (sessionState == SessionState_Unlocked)
      {
        break;
      }
    }
    SAFE_RELEASE(machine);
  }

  SysFreeString(machineName);

  return 0;
}

int main(int argc, char **argv)
{
  /* Initialize the COM subsystem. */
  CoInitialize(NULL);

  /* Instantiate the VirtualBox root object. */
  IVirtualBoxClient *virtualBoxClient;
  HRESULT rc = CoCreateInstance(CLSID_VirtualBoxClient, /* the VirtualBoxClient object */
                                NULL,                   /* no aggregation */
                                CLSCTX_INPROC_SERVER,   /* the object lives in the current process */
                                IID_IVirtualBoxClient,  /* IID of the interface */
                                (void **)&virtualBoxClient);
  if (SUCCEEDED(rc))
  {
    IVirtualBox *virtualBox;
    rc = virtualBoxClient->get_VirtualBox(&virtualBox);
    if (SUCCEEDED(rc))
    {
      for (int i = 0; i < 10; ++i)
      {
        printf("Test run %d\n", i);
        testStartVM(virtualBox, L"TESTING", L"headless");
      }

      /* Release the VirtualBox object. */
      virtualBox->Release();
      virtualBoxClient->Release();
    }
    else
    {
      printf("Error creating VirtualBox instance! rc = 0x%x\n", rc);
      printErrorInfo();
    }
  }

  CoUninitialize();
  return 0;
}


This simple test works fine on VirtualBox 6.0 but on 6.1 the machine state change correctly to PowerOff but the session is never unlocked and the VBoxHeadless.exe process is not killed and I need to kill it from task manager.
If I use a "gui" session type than all works as exepected also in 6.1.

I think that the problem is caused by the event loop of VBoxHeadless because I see that it is started after I triggrer PowerDown command from the console.

TESTING-2022-04-21-14-15-29.log
(107.99 KiB) Downloaded 5 times

Code: Select all   Expand viewCollapse view
00:00:01.819978 Changing the VM state from 'DESTROYING' to 'TERMINATED'
00:00:01.824010 Console: Machine state changed to 'PoweredOff'
00:00:01.937393 VBoxHeadless: starting event loop


Question: do you think that I am doing some errors? Or this is a bug on VirtualBox 6.1.

Attached the code and the log.

Thanks.
mbono
 
Posts: 2
Joined: 21. Apr 2022, 14:02

Re: SessionState never unlocked

Postby fth0 » 21. Apr 2022, 16:23

I have no practical experience with programmatically running a VM, but the following came to mind:

In the loop waiting for the Machine to reach the Running state, does it help to insert a pause (e.g. 100 ms or 1 s) between successive requests?

When trying the Headless mode in the past from within the VirtualBox Manager 6.1, I discovered that the Show action didn't seem to work for non-trivial VMs. Does it help not to call machine->ShowConsoleWindow(0)?
fth0
Volunteer
 
Posts: 3673
Joined: 14. Feb 2019, 03:06
Location: Germany
Primary OS: Mac OS X other
VBox Version: PUEL
Guest OSses: Linux, Windows 10, ...

Re: SessionState never unlocked

Postby mbono » 22. Apr 2022, 12:00

In the real code (this is just a sample that reproduce the problem) I have a sleep between request and I do not use ShowConsoleWindow.
mbono
 
Posts: 2
Joined: 21. Apr 2022, 14:02

Re: SessionState never unlocked

Postby noteirak » 24. Apr 2022, 11:13

You need to wait indeed, any operation on VMs can take a "long" time.
Example of how to do it in Java, but the principle is the same: https://github.com/hyperbox/server/blob ... e.java#L53
Hyperbox - Virtual Infrastructure Manager - https://kamax.io/hbox/
Manage your VirtualBox infrastructure the free way!
noteirak
Site Moderator
 
Posts: 5210
Joined: 13. Jan 2012, 11:14
Primary OS: Debian other
VBox Version: OSE Debian
Guest OSses: Debian, Win 2k8, Win 7


Return to The VirtualBox API

Who is online

Users browsing this forum: No registered users and 2 guests