summaryrefslogtreecommitdiff
path: root/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp')
-rw-r--r--src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp211
1 files changed, 130 insertions, 81 deletions
diff --git a/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp b/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp
index 4a6d62f5..bca3b245 100644
--- a/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp
+++ b/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp
@@ -21,7 +21,7 @@
#include <VBox/com/Guid.h>
#include <VBox/com/ErrorInfo.h>
#include <VBox/com/errorprint.h>
-#include <VBox/com/EventQueue.h>
+#include <VBox/com/NativeEventQueue.h>
#include <VBox/com/VirtualBox.h>
#include <VBox/com/listeners.h>
@@ -73,7 +73,7 @@ using namespace com;
/* global weak references (for event handlers) */
static IConsole *gConsole = NULL;
-static EventQueue *gEventQ = NULL;
+static NativeEventQueue *gEventQ = NULL;
/* flag whether frontend should terminate */
static volatile bool g_fTerminateFE = false;
@@ -164,93 +164,129 @@ public:
{
case VBoxEventType_OnGuestPropertyChanged:
{
- ComPtr<IGuestPropertyChangedEvent> gpcev = aEvent;
- Assert(gpcev);
+ ComPtr<IGuestPropertyChangedEvent> pChangedEvent = aEvent;
+ Assert(pChangedEvent);
- Bstr aKey;
- gpcev->COMGETTER(Name)(aKey.asOutParam());
+ HRESULT hrc;
- if (aKey == Bstr("/VirtualBox/GuestInfo/OS/NoLoggedInUsers"))
+ ComPtr <IMachine> pMachine;
+ if (gConsole)
{
- /* Check if this is our machine and the "disconnect on logout feature" is enabled. */
- BOOL fProcessDisconnectOnGuestLogout = FALSE;
- ComPtr <IMachine> machine;
- HRESULT hrc = S_OK;
-
- if (gConsole)
+ hrc = gConsole->COMGETTER(Machine)(pMachine.asOutParam());
+ if (SUCCEEDED(hrc) && pMachine)
{
- hrc = gConsole->COMGETTER(Machine)(machine.asOutParam());
- if (SUCCEEDED(hrc) && machine)
- {
- Bstr id, machineId;
- hrc = machine->COMGETTER(Id)(id.asOutParam());
- gpcev->COMGETTER(MachineId)(machineId.asOutParam());
- if (id == machineId)
- {
- Bstr value1;
- hrc = machine->GetExtraData(Bstr("VRDP/DisconnectOnGuestLogout").raw(),
- value1.asOutParam());
- if (SUCCEEDED(hrc) && value1 == "1")
- {
- fProcessDisconnectOnGuestLogout = TRUE;
- }
- }
- }
+ Bstr gpMachineId, machineId;
+ hrc = pMachine->COMGETTER(Id)(gpMachineId.asOutParam());
+ AssertComRC(hrc);
+ hrc = pChangedEvent->COMGETTER(MachineId)(machineId.asOutParam());
+ AssertComRC(hrc);
+ if (gpMachineId != machineId)
+ hrc = VBOX_E_OBJECT_NOT_FOUND;
}
+ }
+ else
+ hrc = VBOX_E_INVALID_VM_STATE;
+
+ if (SUCCEEDED(hrc))
+ {
+ Bstr strKey;
+ hrc = pChangedEvent->COMGETTER(Name)(strKey.asOutParam());
+ AssertComRC(hrc);
+
+ Bstr strValue;
+ hrc = pChangedEvent->COMGETTER(Value)(strValue.asOutParam());
+ AssertComRC(hrc);
- if (fProcessDisconnectOnGuestLogout)
+ Utf8Str utf8Key = strKey;
+ Utf8Str utf8Value = strValue;
+ LogRelFlow(("Guest property \"%s\" has been changed to \"%s\"\n",
+ utf8Key.c_str(), utf8Value.c_str()));
+
+ if (utf8Key.equals("/VirtualBox/GuestInfo/OS/NoLoggedInUsers"))
{
- bool fDropConnection = false;
+ LogRelFlow(("Guest indicates that there %s logged in users\n",
+ utf8Value.equals("true") ? "are no" : "are"));
- Bstr value;
- gpcev->COMGETTER(Value)(value.asOutParam());
- Utf8Str utf8Value = value;
+ /* Check if this is our machine and the "disconnect on logout feature" is enabled. */
+ BOOL fProcessDisconnectOnGuestLogout = FALSE;
- if (!mfNoLoggedInUsers) /* Only if the property really changes. */
+ /* Does the machine handle VRDP disconnects? */
+ Bstr strDiscon;
+ hrc = pMachine->GetExtraData(Bstr("VRDP/DisconnectOnGuestLogout").raw(),
+ strDiscon.asOutParam());
+ if (SUCCEEDED(hrc))
{
- if ( utf8Value == "true"
- /* Guest property got deleted due to reset,
- * so it has no value anymore. */
- || utf8Value.isEmpty())
- {
- mfNoLoggedInUsers = true;
- fDropConnection = true;
- }
+ Utf8Str utf8Discon = strDiscon;
+ fProcessDisconnectOnGuestLogout = utf8Discon.equals("1")
+ ? TRUE : FALSE;
}
- else if (utf8Value == "false")
- mfNoLoggedInUsers = false;
- /* Guest property got deleted due to reset,
- * take the shortcut without touching the mfNoLoggedInUsers
- * state. */
- else if (utf8Value.isEmpty())
- fDropConnection = true;
-
- if (fDropConnection)
+
+ LogRelFlow(("VRDE: hrc=%Rhrc: Host %s disconnecting clients (current host state known: %s)\n",
+ hrc, fProcessDisconnectOnGuestLogout ? "will handle" : "does not handle",
+ mfNoLoggedInUsers ? "No users logged in" : "Users logged in"));
+
+ if (fProcessDisconnectOnGuestLogout)
{
- /* If there is a connection, drop it. */
- ComPtr<IVRDEServerInfo> info;
- hrc = gConsole->COMGETTER(VRDEServerInfo)(info.asOutParam());
- if (SUCCEEDED(hrc) && info)
+ bool fDropConnection = false;
+ if (!mfNoLoggedInUsers) /* Only if the property really changes. */
+ {
+ if ( utf8Value == "true"
+ /* Guest property got deleted due to reset,
+ * so it has no value anymore. */
+ || utf8Value.isEmpty())
+ {
+ mfNoLoggedInUsers = true;
+ fDropConnection = true;
+ }
+ }
+ else if (utf8Value == "false")
+ mfNoLoggedInUsers = false;
+ /* Guest property got deleted due to reset,
+ * take the shortcut without touching the mfNoLoggedInUsers
+ * state. */
+ else if (utf8Value.isEmpty())
+ fDropConnection = true;
+
+ LogRelFlow(("VRDE: szNoLoggedInUsers=%s, mfNoLoggedInUsers=%RTbool, fDropConnection=%RTbool\n",
+ utf8Value.c_str(), mfNoLoggedInUsers, fDropConnection));
+
+ if (fDropConnection)
{
- ULONG cClients = 0;
- hrc = info->COMGETTER(NumberOfClients)(&cClients);
- if (SUCCEEDED(hrc) && cClients > 0)
+ /* If there is a connection, drop it. */
+ ComPtr<IVRDEServerInfo> info;
+ hrc = gConsole->COMGETTER(VRDEServerInfo)(info.asOutParam());
+ if (SUCCEEDED(hrc) && info)
{
- ComPtr <IVRDEServer> vrdeServer;
- hrc = machine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
- if (SUCCEEDED(hrc) && vrdeServer)
+ ULONG cClients = 0;
+ hrc = info->COMGETTER(NumberOfClients)(&cClients);
+
+ LogRelFlow(("VRDE: connected clients=%RU32\n", cClients));
+ if (SUCCEEDED(hrc) && cClients > 0)
{
- LogRel(("VRDE: the guest user has logged out, disconnecting remote clients.\n"));
- vrdeServer->COMSETTER(Enabled)(FALSE);
- vrdeServer->COMSETTER(Enabled)(TRUE);
+ ComPtr <IVRDEServer> vrdeServer;
+ hrc = pMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
+ if (SUCCEEDED(hrc) && vrdeServer)
+ {
+ LogRel(("VRDE: the guest user has logged out, disconnecting remote clients.\n"));
+ hrc = vrdeServer->COMSETTER(Enabled)(FALSE);
+ AssertComRC(hrc);
+ HRESULT hrc2 = vrdeServer->COMSETTER(Enabled)(TRUE);
+ if (SUCCEEDED(hrc))
+ hrc = hrc2;
+ }
}
}
}
}
}
+
+ if (FAILED(hrc))
+ LogRelFlow(("VRDE: returned error=%Rhrc\n", hrc));
}
+
break;
}
+
default:
AssertFailed();
}
@@ -259,6 +295,7 @@ public:
}
private:
+
bool mfNoLoggedInUsers;
};
@@ -295,7 +332,7 @@ public:
{
ComPtr<IMouseCapabilityChangedEvent> mccev = aEvent;
- Assert(mccev);
+ Assert(!mccev.isNull());
BOOL fSupportsAbsolute = false;
mccev->COMGETTER(SupportsAbsolute)(&fSupportsAbsolute);
@@ -496,7 +533,12 @@ static void parse_environ(unsigned long *pulFrameWidth, unsigned long *pulFrameH
unsigned long *pulBitRate, const char **ppszFileName)
{
const char *pszEnvTemp;
-
+/** @todo r=bird: This isn't up to scratch. The life time of an RTEnvGet
+ * return value is only up to the next RTEnv*, *getenv, *putenv,
+ * setenv call in _any_ process in the system and the it has known and
+ * documented code page issues.
+ *
+ * Use RTEnvGetEx instead! */
if ((pszEnvTemp = RTEnvGet("VBOX_CAPTUREWIDTH")) != 0)
{
errno = 0;
@@ -612,18 +654,18 @@ extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
unsigned fPATM = ~0U;
unsigned fCSAM = ~0U;
#ifdef VBOX_WITH_VIDEO_REC
- unsigned fVIDEOREC = 0;
+ bool fVideoRec = 0;
unsigned long ulFrameWidth = 800;
unsigned long ulFrameHeight = 600;
- unsigned long ulBitRate = 300000;
- char pszMPEGFile[RTPATH_MAX];
+ unsigned long ulBitRate = 300000; /** @todo r=bird: The COM type ULONG isn't unsigned long, it's 32-bit unsigned int. */
+ char szMpegFile[RTPATH_MAX];
const char *pszFileNameParam = "VBox-%d.vob";
#endif /* VBOX_WITH_VIDEO_REC */
- LogFlow (("VBoxHeadless STARTED.\n"));
- RTPrintf (VBOX_PRODUCT " Headless Interface " VBOX_VERSION_STRING "\n"
- "(C) 2008-" VBOX_C_YEAR " " VBOX_VENDOR "\n"
- "All rights reserved.\n\n");
+ LogFlow(("VBoxHeadless STARTED.\n"));
+ RTPrintf(VBOX_PRODUCT " Headless Interface " VBOX_VERSION_STRING "\n"
+ "(C) 2008-" VBOX_C_YEAR " " VBOX_VENDOR "\n"
+ "All rights reserved.\n\n");
#ifdef VBOX_WITH_VIDEO_REC
/* Parse the environment */
@@ -754,7 +796,7 @@ extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
break;
#ifdef VBOX_WITH_VIDEO_REC
case 'c':
- fVIDEOREC = true;
+ fVideoRec = true;
break;
case 'w':
ulFrameWidth = ValueUnion.u32;
@@ -818,7 +860,7 @@ extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
LogError("VBoxHeadless: ERROR: Only one format modifier is allowed in the capture file name.", -1);
return 1;
}
- RTStrPrintf(&pszMPEGFile[0], RTPATH_MAX, pszFileNameParam, RTProcSelf());
+ RTStrPrintf(&szMpegFile[0], RTPATH_MAX, pszFileNameParam, RTProcSelf());
#endif /* defined VBOX_WITH_VIDEO_REC */
if (!pcszNameOrUUID)
@@ -933,7 +975,7 @@ extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
RTLDRMOD hLdrVideoRecFB;
PFNREGISTERVIDEORECFB pfnRegisterVideoRecFB;
- if (fVIDEOREC)
+ if (fVideoRec)
{
HRESULT rcc = S_OK;
int rrc = VINF_SUCCESS;
@@ -957,7 +999,7 @@ extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
{
Log2(("VBoxHeadless: calling pfnRegisterVideoRecFB\n"));
rcc = pfnRegisterVideoRecFB(ulFrameWidth, ulFrameHeight, ulBitRate,
- pszMPEGFile, &pFramebuffer);
+ szMpegFile, &pFramebuffer);
if (rcc != S_OK)
LogError("Failed to initialise video capturing - make sure that the file format\n"
"you wish to use is supported on your system\n", rcc);
@@ -983,7 +1025,7 @@ extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
for (uScreenId = 0; uScreenId < cMonitors; uScreenId++)
{
# ifdef VBOX_WITH_VIDEO_REC
- if (fVIDEOREC && uScreenId == 0)
+ if (fVideoRec && uScreenId == 0)
{
/* Already registered. */
continue;
@@ -1067,7 +1109,7 @@ extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
/* initialize global references */
gConsole = console;
- gEventQ = com::EventQueue::getMainEventQueue();
+ gEventQ = com::NativeEventQueue::getMainEventQueue();
/* VirtualBoxClient events registration. */
{
@@ -1251,6 +1293,13 @@ extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
vboxListener = listener;
com::SafeArray<VBoxEventType_T> eventTypes;
eventTypes.push_back(VBoxEventType_OnGuestPropertyChanged);
+
+ /**
+ * @todo Set the notification pattern to "/VirtualBox/GuestInfo/OS/ *Logged*"
+ * to not cause too much load. The current API is broken as
+ * IMachine::GuestPropertyNotificationPatterns() would change the
+ * filter for _all_ clients. This is not what we want!
+ */
CHECK_ERROR(es, RegisterListener(vboxListener, ComSafeArrayAsInParam(eventTypes), true));
}