SessionState never unlocked

Discussion about using the VirtualBox API, Tutorials, Samples.
Post Reply
mbono
Posts: 2
Joined: 21. Apr 2022, 14:02

SessionState never unlocked

Post by mbono »

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 24 times

Code: Select all

#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 20 times

Code: Select all

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.
fth0
Volunteer
Posts: 5661
Joined: 14. Feb 2019, 03:06
Primary OS: Mac OS X other
VBox Version: PUEL
Guest OSses: Linux, Windows 10, ...
Location: Germany

Re: SessionState never unlocked

Post by fth0 »

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)?
mbono
Posts: 2
Joined: 21. Apr 2022, 14:02

Re: SessionState never unlocked

Post by mbono »

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.
noteirak
Site Moderator
Posts: 5229
Joined: 13. Jan 2012, 11:14
Primary OS: Debian other
VBox Version: OSE Debian
Guest OSses: Debian, Win 2k8, Win 7
Contact:

Re: SessionState never unlocked

Post by noteirak »

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://apps.kamax.lu/hyperbox/
Manage your VirtualBox infrastructure the free way!
Post Reply