summaryrefslogtreecommitdiff
path: root/src/VBox/Main/src-server
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Main/src-server')
-rw-r--r--src/VBox/Main/src-server/ApplianceImpl.cpp263
-rw-r--r--src/VBox/Main/src-server/ApplianceImplExport.cpp781
-rw-r--r--src/VBox/Main/src-server/ApplianceImplIO.cpp191
-rw-r--r--src/VBox/Main/src-server/ApplianceImplImport.cpp1867
-rw-r--r--src/VBox/Main/src-server/AudioAdapterImpl.cpp2
-rw-r--r--src/VBox/Main/src-server/BIOSSettingsImpl.cpp19
-rw-r--r--src/VBox/Main/src-server/BandwidthControlImpl.cpp26
-rw-r--r--src/VBox/Main/src-server/BandwidthGroupImpl.cpp9
-rw-r--r--src/VBox/Main/src-server/ClientToken.cpp262
-rw-r--r--src/VBox/Main/src-server/ClientWatcher.cpp849
-rw-r--r--src/VBox/Main/src-server/DHCPServerImpl.cpp372
-rw-r--r--src/VBox/Main/src-server/HostDnsService.cpp363
-rw-r--r--src/VBox/Main/src-server/HostDnsService.h236
-rw-r--r--src/VBox/Main/src-server/HostDnsServiceResolvConf.cpp91
-rw-r--r--src/VBox/Main/src-server/HostImpl.cpp503
-rw-r--r--src/VBox/Main/src-server/HostNetworkInterfaceImpl.cpp57
-rw-r--r--src/VBox/Main/src-server/HostPower.cpp144
-rw-r--r--src/VBox/Main/src-server/HostVideoInputDeviceImpl.cpp235
-rw-r--r--src/VBox/Main/src-server/MachineImpl.cpp2706
-rw-r--r--src/VBox/Main/src-server/MachineImplCloneVM.cpp50
-rw-r--r--src/VBox/Main/src-server/Matching.cpp2
-rw-r--r--src/VBox/Main/src-server/MediumAttachmentImpl.cpp42
-rw-r--r--src/VBox/Main/src-server/MediumFormatImpl.cpp146
-rw-r--r--src/VBox/Main/src-server/MediumImpl.cpp820
-rw-r--r--src/VBox/Main/src-server/MediumLock.cpp38
-rw-r--r--src/VBox/Main/src-server/NATEngineImpl.cpp4
-rw-r--r--src/VBox/Main/src-server/NATNetworkImpl.cpp1115
-rw-r--r--src/VBox/Main/src-server/NATNetworkServiceRunner.cpp (renamed from src/VBox/Main/src-server/DHCPServerRunner.cpp)70
-rw-r--r--src/VBox/Main/src-server/NetworkAdapterImpl.cpp111
-rw-r--r--src/VBox/Main/src-server/NetworkServiceRunner.cpp138
-rw-r--r--src/VBox/Main/src-server/ParallelPortImpl.cpp2
-rw-r--r--src/VBox/Main/src-server/Performance.cpp257
-rw-r--r--src/VBox/Main/src-server/PerformanceImpl.cpp2
-rw-r--r--src/VBox/Main/src-server/ProgressProxyImpl.cpp2
-rw-r--r--src/VBox/Main/src-server/SerialPortImpl.cpp2
-rw-r--r--src/VBox/Main/src-server/SnapshotImpl.cpp499
-rw-r--r--src/VBox/Main/src-server/StorageControllerImpl.cpp2
-rw-r--r--src/VBox/Main/src-server/SystemPropertiesImpl.cpp203
-rw-r--r--src/VBox/Main/src-server/TokenImpl.cpp217
-rw-r--r--src/VBox/Main/src-server/USBControllerImpl.cpp1010
-rw-r--r--src/VBox/Main/src-server/USBDeviceFilterImpl.cpp12
-rw-r--r--src/VBox/Main/src-server/USBDeviceFiltersImpl.cpp1089
-rw-r--r--src/VBox/Main/src-server/VFSExplorerImpl.cpp6
-rw-r--r--src/VBox/Main/src-server/VRDEServerImpl.cpp107
-rw-r--r--src/VBox/Main/src-server/VirtualBoxImpl.cpp1235
-rw-r--r--src/VBox/Main/src-server/darwin/HostDnsServiceDarwin.cpp256
-rw-r--r--src/VBox/Main/src-server/darwin/HostPowerDarwin.cpp118
-rw-r--r--src/VBox/Main/src-server/darwin/NetIf-darwin.cpp23
-rw-r--r--src/VBox/Main/src-server/darwin/PerformanceDarwin.cpp67
-rw-r--r--src/VBox/Main/src-server/darwin/iokit.cpp6
-rw-r--r--src/VBox/Main/src-server/darwin/iokit.h2
-rw-r--r--src/VBox/Main/src-server/freebsd/HostHardwareFreeBSD.cpp13
-rw-r--r--src/VBox/Main/src-server/freebsd/NetIf-freebsd.cpp22
-rw-r--r--src/VBox/Main/src-server/freebsd/PerformanceFreeBSD.cpp13
-rw-r--r--src/VBox/Main/src-server/freebsd/USBProxyServiceFreeBSD.cpp2
-rw-r--r--src/VBox/Main/src-server/generic/AutostartDb-generic.cpp4
-rw-r--r--src/VBox/Main/src-server/generic/NetIf-generic.cpp51
-rw-r--r--src/VBox/Main/src-server/linux/HostDnsServiceLinux.cpp233
-rw-r--r--src/VBox/Main/src-server/linux/HostHardwareLinux.cpp5
-rw-r--r--src/VBox/Main/src-server/linux/NetIf-linux.cpp133
-rw-r--r--src/VBox/Main/src-server/linux/PerformanceLinux.cpp336
-rw-r--r--src/VBox/Main/src-server/linux/USBGetDevices.cpp16
-rw-r--r--src/VBox/Main/src-server/linux/USBProxyServiceLinux.cpp2
-rw-r--r--src/VBox/Main/src-server/linux/vbox-libhal.cpp2
-rw-r--r--src/VBox/Main/src-server/os2/NetIf-os2.cpp11
-rw-r--r--src/VBox/Main/src-server/os2/PerformanceOs2.cpp15
-rw-r--r--src/VBox/Main/src-server/solaris/DynLoadLibSolaris.cpp2
-rw-r--r--src/VBox/Main/src-server/solaris/DynLoadLibSolaris.h2
-rw-r--r--src/VBox/Main/src-server/solaris/NetIf-solaris.cpp133
-rw-r--r--src/VBox/Main/src-server/solaris/PerformanceSolaris.cpp530
-rw-r--r--src/VBox/Main/src-server/solaris/USBProxyServiceSolaris.cpp6
-rw-r--r--src/VBox/Main/src-server/win/HostDnsServiceWin.cpp233
-rw-r--r--src/VBox/Main/src-server/win/HostPowerWin.cpp38
-rw-r--r--src/VBox/Main/src-server/win/NetIf-win.cpp37
-rw-r--r--src/VBox/Main/src-server/win/PerformanceWin.cpp84
-rw-r--r--src/VBox/Main/src-server/win/svchlp.cpp2
-rw-r--r--src/VBox/Main/src-server/win/svchlp.h2
-rw-r--r--src/VBox/Main/src-server/win/svcmain.cpp17
-rw-r--r--src/VBox/Main/src-server/xpcom/server.cpp45
-rw-r--r--src/VBox/Main/src-server/xpcom/server.h2
-rw-r--r--src/VBox/Main/src-server/xpcom/server_module.cpp92
81 files changed, 14122 insertions, 4590 deletions
diff --git a/src/VBox/Main/src-server/ApplianceImpl.cpp b/src/VBox/Main/src-server/ApplianceImpl.cpp
index 05fc3b67..8d1e6014 100644
--- a/src/VBox/Main/src-server/ApplianceImpl.cpp
+++ b/src/VBox/Main/src-server/ApplianceImpl.cpp
@@ -1,11 +1,10 @@
/* $Id: ApplianceImpl.cpp $ */
/** @file
- *
* IAppliance and IVirtualSystem COM class implementations.
*/
/*
- * Copyright (C) 2008-2012 Oracle Corporation
+ * Copyright (C) 2008-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -18,8 +17,8 @@
#include <iprt/path.h>
#include <iprt/cpp/utils.h>
-
#include <VBox/com/array.h>
+#include <map>
#include "ApplianceImpl.h"
#include "VFSExplorerImpl.h"
@@ -28,7 +27,8 @@
#include "Global.h"
#include "ProgressImpl.h"
#include "MachineImpl.h"
-
+#include "MediumFormatImpl.h"
+#include "SystemPropertiesImpl.h"
#include "AutoCaller.h"
#include "Logging.h"
@@ -42,6 +42,21 @@ using namespace std;
//
////////////////////////////////////////////////////////////////////////////////
+static const char* const strISOURI = "http://www.ecma-international.org/publications/standards/Ecma-119.htm";
+static const char* const strVMDKStreamURI = "http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized";
+static const char* const strVMDKSparseURI = "http://www.vmware.com/specifications/vmdk.html#sparse";
+static const char* const strVMDKCompressedURI = "http://www.vmware.com/specifications/vmdk.html#compressed";
+static const char* const strVMDKCompressedURI2 = "http://www.vmware.com/interfaces/specifications/vmdk.html#compressed";
+static const char* const strVHDURI = "http://go.microsoft.com/fwlink/?LinkId=137171";
+
+static std::map<Utf8Str, Utf8Str> supportedStandardsURI;
+
+static const char* const applianceIOTarName = "Appliance::IOTar";
+static const char* const applianceIOShaName = "Appliance::IOSha";
+static const char* const applianceIOFileName = "Appliance::IOFile";
+
+static std::map<APPLIANCEIONAME, Utf8Str> applianceIONameMap;
+
static const struct
{
ovf::CIMOSType_T cim;
@@ -83,6 +98,11 @@ g_osTypes[] =
{ ovf::CIMOSType_CIMOS_FreeBSD_64, VBOXOSTYPE_FreeBSD_x64 },
{ ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS },
{ ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS_x64 }, // there is no CIM 64-bit type for this
+ { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS106 },
+ { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS106_x64 },
+ { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS107_x64 },
+ { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS108_x64 },
+ { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS109_x64 },
// Linuxes
{ ovf::CIMOSType_CIMOS_RedHatEnterpriseLinux, VBOXOSTYPE_RedHat },
@@ -238,24 +258,44 @@ void convertCIMOSType2VBoxOSType(Utf8Str &strType, ovf::CIMOSType_T c, const Utf
}
}
- strType = Global::OSTypeId(VBOXOSTYPE_Unknown);
+ if (c == ovf::CIMOSType_CIMOS_Other_64)
+ strType = Global::OSTypeId(VBOXOSTYPE_Unknown_x64);
+ else
+ strType = Global::OSTypeId(VBOXOSTYPE_Unknown);
}
/**
* Private helper func that suggests a VirtualBox guest OS type
* for the given OVF operating system type.
- * @param osTypeVBox
- * @param c
+ * @returns CIM OS type.
+ * @param pcszVBox Our guest OS type identifier string.
+ * @param fLongMode Whether long mode is enabled and a 64-bit CIM type is
+ * preferred even if the VBox guest type isn't 64-bit.
*/
-ovf::CIMOSType_T convertVBoxOSType2CIMOSType(const char *pcszVbox)
+ovf::CIMOSType_T convertVBoxOSType2CIMOSType(const char *pcszVBox, BOOL fLongMode)
{
for (size_t i = 0; i < RT_ELEMENTS(g_osTypes); ++i)
{
- if (!RTStrICmp(pcszVbox, Global::OSTypeId(g_osTypes[i].osType)))
+ if (!RTStrICmp(pcszVBox, Global::OSTypeId(g_osTypes[i].osType)))
+ {
+ if (fLongMode && !(g_osTypes[i].osType & VBOXOSTYPE_x64))
+ {
+ VBOXOSTYPE enmDesiredOsType = (VBOXOSTYPE)((int)g_osTypes[i].osType | (int)VBOXOSTYPE_x64);
+ size_t j = i;
+ while (++j < RT_ELEMENTS(g_osTypes))
+ if (g_osTypes[j].osType == enmDesiredOsType)
+ return g_osTypes[j].cim;
+ j = i;
+ while (--j > 0)
+ if (g_osTypes[j].osType == enmDesiredOsType)
+ return g_osTypes[j].cim;
+ /* Not all OSes have 64-bit versions, so just return the 32-bit variant. */
+ }
return g_osTypes[i].cim;
+ }
}
- return ovf::CIMOSType_CIMOS_Other;
+ return fLongMode ? ovf::CIMOSType_CIMOS_Other_64 : ovf::CIMOSType_CIMOS_Other;
}
Utf8Str convertNetworkAttachmentTypeToString(NetworkAttachmentType_T type)
@@ -268,6 +308,7 @@ Utf8Str convertNetworkAttachmentTypeToString(NetworkAttachmentType_T type)
case NetworkAttachmentType_Internal: strType = "Internal"; break;
case NetworkAttachmentType_HostOnly: strType = "HostOnly"; break;
case NetworkAttachmentType_Generic: strType = "Generic"; break;
+ case NetworkAttachmentType_NATNetwork: strType = "NATNetwork"; break;
case NetworkAttachmentType_Null: strType = "Null"; break;
}
return strType;
@@ -324,6 +365,7 @@ Appliance::~Appliance()
*/
HRESULT Appliance::init(VirtualBox *aVirtualBox)
{
+ HRESULT rc = S_OK;
/* Enclose the state transition NotReady->InInit->Ready */
AutoInitSpan autoInitSpan(this);
AssertReturn(autoInitSpan.isOk(), E_FAIL);
@@ -334,10 +376,14 @@ HRESULT Appliance::init(VirtualBox *aVirtualBox)
// initialize data
m = new Data;
+ initApplianceIONameMap();
+
+ rc = initSetOfSupportedStandardsURI();
+
/* Confirm a successful initialization */
autoInitSpan.setSucceeded();
- return S_OK;
+ return rc;
}
/**
@@ -573,6 +619,113 @@ STDMETHODIMP Appliance::GetWarnings(ComSafeArrayOut(BSTR, aWarnings))
//
////////////////////////////////////////////////////////////////////////////////
+HRESULT Appliance::initSetOfSupportedStandardsURI()
+{
+ HRESULT rc = S_OK;
+ if (!supportedStandardsURI.empty())
+ return rc;
+
+ /* Get the system properties. */
+ SystemProperties *pSysProps = mVirtualBox->getSystemProperties();
+ {
+ ComObjPtr<MediumFormat> trgFormat = pSysProps->mediumFormatFromExtension("iso");
+ if (trgFormat.isNull())
+ return setError(E_FAIL, tr("Can't find appropriate medium format for ISO type of a virtual disk."));
+
+ Bstr bstrFormatName;
+ rc = trgFormat->COMGETTER(Name)(bstrFormatName.asOutParam());
+ if (FAILED(rc)) return rc;
+
+ Utf8Str strTrgFormat = Utf8Str(bstrFormatName);
+
+ supportedStandardsURI.insert(std::make_pair(Utf8Str(strISOURI), strTrgFormat));
+ }
+
+ {
+ ComObjPtr<MediumFormat> trgFormat = pSysProps->mediumFormatFromExtension("vmdk");
+ if (trgFormat.isNull())
+ return setError(E_FAIL, tr("Can't find appropriate medium format for VMDK type of a virtual disk."));
+
+ Bstr bstrFormatName;
+ rc = trgFormat->COMGETTER(Name)(bstrFormatName.asOutParam());
+ if (FAILED(rc)) return rc;
+
+ Utf8Str strTrgFormat = Utf8Str(bstrFormatName);
+
+ supportedStandardsURI.insert(std::make_pair(Utf8Str(strVMDKStreamURI), strTrgFormat));
+ supportedStandardsURI.insert(std::make_pair(Utf8Str(strVMDKSparseURI), strTrgFormat));
+ supportedStandardsURI.insert(std::make_pair(Utf8Str(strVMDKCompressedURI), strTrgFormat));
+ supportedStandardsURI.insert(std::make_pair(Utf8Str(strVMDKCompressedURI2), strTrgFormat));
+ }
+
+ {
+ ComObjPtr<MediumFormat> trgFormat = pSysProps->mediumFormatFromExtension("vhd");
+ if (trgFormat.isNull())
+ return setError(E_FAIL, tr("Can't find appropriate medium format for VHD type of a virtual disk."));
+
+ Bstr bstrFormatName;
+ rc = trgFormat->COMGETTER(Name)(bstrFormatName.asOutParam());
+ if (FAILED(rc)) return rc;
+
+ Utf8Str strTrgFormat = Utf8Str(bstrFormatName);
+
+ supportedStandardsURI.insert(std::make_pair(Utf8Str(strVHDURI), strTrgFormat));
+ }
+
+ return rc;
+}
+
+Utf8Str Appliance::typeOfVirtualDiskFormatFromURI(Utf8Str uri) const
+{
+ Utf8Str type;
+ std::map<Utf8Str, Utf8Str>::const_iterator cit = supportedStandardsURI.find(uri);
+ if (cit != supportedStandardsURI.end())
+ {
+ type = cit->second;
+ }
+
+ return type;
+}
+
+std::set<Utf8Str> Appliance::URIFromTypeOfVirtualDiskFormat(Utf8Str type)
+{
+ std::set<Utf8Str> uri;
+ std::map<Utf8Str, Utf8Str>::const_iterator cit = supportedStandardsURI.begin();
+ while(cit != supportedStandardsURI.end())
+ {
+ if (cit->second.compare(type,Utf8Str::CaseInsensitive) == 0)
+ uri.insert(cit->first);
+ ++cit;
+ }
+
+ return uri;
+}
+
+HRESULT Appliance::initApplianceIONameMap()
+{
+ HRESULT rc = S_OK;
+ if (!applianceIONameMap.empty())
+ return rc;
+
+ applianceIONameMap.insert(std::make_pair(applianceIOTar, applianceIOTarName));
+ applianceIONameMap.insert(std::make_pair(applianceIOFile, applianceIOFileName));
+ applianceIONameMap.insert(std::make_pair(applianceIOSha, applianceIOShaName));
+
+ return rc;
+}
+
+Utf8Str Appliance::applianceIOName(APPLIANCEIONAME type) const
+{
+ Utf8Str name;
+ std::map<APPLIANCEIONAME, Utf8Str>::const_iterator cit = applianceIONameMap.find(type);
+ if (cit != applianceIONameMap.end())
+ {
+ name = cit->second;
+ }
+
+ return name;
+}
+
/**
* Returns true if the appliance is in "idle" state. This should always be the
* case unless an import or export is currently in progress. Similar to machine
@@ -626,7 +779,7 @@ HRESULT Appliance::searchUniqueDiskImageFilePath(Utf8Str& aName) const
* already */
/** @todo: Maybe too cost-intensive; try to find a lighter way */
while ( RTPathExists(tmpName)
- || mVirtualBox->OpenMedium(Bstr(tmpName).raw(), DeviceType_HardDisk, AccessMode_ReadWrite, FALSE /* fForceNewUuid */, &harddisk) != VBOX_E_OBJECT_NOT_FOUND
+ || mVirtualBox->OpenMedium(Bstr(tmpName).raw(), DeviceType_HardDisk, AccessMode_ReadWrite, FALSE /* fForceNewUuid */, &harddisk) != VBOX_E_OBJECT_NOT_FOUND
)
{
RTStrFree(tmpName);
@@ -783,7 +936,7 @@ void Appliance::waitForAsyncProgress(ComObjPtr<Progress> &pProgressThis,
that in the meantime more than one async operation was finished. So
we have to loop as long as we reached the same operation count. */
ULONG curOp;
- for(;;)
+ for (;;)
{
rc = pProgressAsync->COMGETTER(Operation(&curOp));
if (FAILED(rc)) throw rc;
@@ -866,6 +1019,16 @@ void Appliance::disksWeight()
m->ulTotalDisksMB += pHD->ulSizeMB;
++m->cDisks;
}
+
+ avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_CDROM);
+ for (itH = avsdeHDs.begin();
+ itH != avsdeHDs.end();
+ ++itH)
+ {
+ const VirtualSystemDescriptionEntry *pHD = *itH;
+ m->ulTotalDisksMB += pHD->ulSizeMB;
+ ++m->cDisks;
+ }
}
}
@@ -1109,13 +1272,13 @@ STDMETHODIMP VirtualSystemDescription::COMGETTER(Count)(ULONG *aCount)
STDMETHODIMP VirtualSystemDescription::GetDescription(ComSafeArrayOut(VirtualSystemDescriptionType_T, aTypes),
ComSafeArrayOut(BSTR, aRefs),
ComSafeArrayOut(BSTR, aOrigValues),
- ComSafeArrayOut(BSTR, aVboxValues),
+ ComSafeArrayOut(BSTR, aVBoxValues),
ComSafeArrayOut(BSTR, aExtraConfigValues))
{
if (ComSafeArrayOutIsNull(aTypes) ||
ComSafeArrayOutIsNull(aRefs) ||
ComSafeArrayOutIsNull(aOrigValues) ||
- ComSafeArrayOutIsNull(aVboxValues) ||
+ ComSafeArrayOutIsNull(aVBoxValues) ||
ComSafeArrayOutIsNull(aExtraConfigValues))
return E_POINTER;
@@ -1128,7 +1291,7 @@ STDMETHODIMP VirtualSystemDescription::GetDescription(ComSafeArrayOut(VirtualSys
com::SafeArray<VirtualSystemDescriptionType_T> sfaTypes(c);
com::SafeArray<BSTR> sfaRefs(c);
com::SafeArray<BSTR> sfaOrigValues(c);
- com::SafeArray<BSTR> sfaVboxValues(c);
+ com::SafeArray<BSTR> sfaVBoxValues(c);
com::SafeArray<BSTR> sfaExtraConfigValues(c);
list<VirtualSystemDescriptionEntry>::const_iterator it;
@@ -1147,8 +1310,8 @@ STDMETHODIMP VirtualSystemDescription::GetDescription(ComSafeArrayOut(VirtualSys
bstr = vsde.strOvf;
bstr.cloneTo(&sfaOrigValues[i]);
- bstr = vsde.strVboxCurrent;
- bstr.cloneTo(&sfaVboxValues[i]);
+ bstr = vsde.strVBoxCurrent;
+ bstr.cloneTo(&sfaVBoxValues[i]);
bstr = vsde.strExtraConfigCurrent;
bstr.cloneTo(&sfaExtraConfigValues[i]);
@@ -1157,7 +1320,7 @@ STDMETHODIMP VirtualSystemDescription::GetDescription(ComSafeArrayOut(VirtualSys
sfaTypes.detachTo(ComSafeArrayOutArg(aTypes));
sfaRefs.detachTo(ComSafeArrayOutArg(aRefs));
sfaOrigValues.detachTo(ComSafeArrayOutArg(aOrigValues));
- sfaVboxValues.detachTo(ComSafeArrayOutArg(aVboxValues));
+ sfaVBoxValues.detachTo(ComSafeArrayOutArg(aVBoxValues));
sfaExtraConfigValues.detachTo(ComSafeArrayOutArg(aExtraConfigValues));
return S_OK;
@@ -1171,13 +1334,13 @@ STDMETHODIMP VirtualSystemDescription::GetDescriptionByType(VirtualSystemDescrip
ComSafeArrayOut(VirtualSystemDescriptionType_T, aTypes),
ComSafeArrayOut(BSTR, aRefs),
ComSafeArrayOut(BSTR, aOrigValues),
- ComSafeArrayOut(BSTR, aVboxValues),
+ ComSafeArrayOut(BSTR, aVBoxValues),
ComSafeArrayOut(BSTR, aExtraConfigValues))
{
if (ComSafeArrayOutIsNull(aTypes) ||
ComSafeArrayOutIsNull(aRefs) ||
ComSafeArrayOutIsNull(aOrigValues) ||
- ComSafeArrayOutIsNull(aVboxValues) ||
+ ComSafeArrayOutIsNull(aVBoxValues) ||
ComSafeArrayOutIsNull(aExtraConfigValues))
return E_POINTER;
@@ -1191,7 +1354,7 @@ STDMETHODIMP VirtualSystemDescription::GetDescriptionByType(VirtualSystemDescrip
com::SafeArray<VirtualSystemDescriptionType_T> sfaTypes(c);
com::SafeArray<BSTR> sfaRefs(c);
com::SafeArray<BSTR> sfaOrigValues(c);
- com::SafeArray<BSTR> sfaVboxValues(c);
+ com::SafeArray<BSTR> sfaVBoxValues(c);
com::SafeArray<BSTR> sfaExtraConfigValues(c);
list<VirtualSystemDescriptionEntry*>::const_iterator it;
@@ -1210,8 +1373,8 @@ STDMETHODIMP VirtualSystemDescription::GetDescriptionByType(VirtualSystemDescrip
bstr = vsde->strOvf;
bstr.cloneTo(&sfaOrigValues[i]);
- bstr = vsde->strVboxCurrent;
- bstr.cloneTo(&sfaVboxValues[i]);
+ bstr = vsde->strVBoxCurrent;
+ bstr.cloneTo(&sfaVBoxValues[i]);
bstr = vsde->strExtraConfigCurrent;
bstr.cloneTo(&sfaExtraConfigValues[i]);
@@ -1220,7 +1383,7 @@ STDMETHODIMP VirtualSystemDescription::GetDescriptionByType(VirtualSystemDescrip
sfaTypes.detachTo(ComSafeArrayOutArg(aTypes));
sfaRefs.detachTo(ComSafeArrayOutArg(aRefs));
sfaOrigValues.detachTo(ComSafeArrayOutArg(aOrigValues));
- sfaVboxValues.detachTo(ComSafeArrayOutArg(aVboxValues));
+ sfaVBoxValues.detachTo(ComSafeArrayOutArg(aVBoxValues));
sfaExtraConfigValues.detachTo(ComSafeArrayOutArg(aExtraConfigValues));
return S_OK;
@@ -1258,7 +1421,7 @@ STDMETHODIMP VirtualSystemDescription::GetValuesByType(VirtualSystemDescriptionT
{
case VirtualSystemDescriptionValueType_Reference: bstr = vsde->strRef; break;
case VirtualSystemDescriptionValueType_Original: bstr = vsde->strOvf; break;
- case VirtualSystemDescriptionValueType_Auto: bstr = vsde->strVboxCurrent; break;
+ case VirtualSystemDescriptionValueType_Auto: bstr = vsde->strVBoxCurrent; break;
case VirtualSystemDescriptionValueType_ExtraConfig: bstr = vsde->strExtraConfigCurrent; break;
}
@@ -1275,7 +1438,7 @@ STDMETHODIMP VirtualSystemDescription::GetValuesByType(VirtualSystemDescriptionT
* @return
*/
STDMETHODIMP VirtualSystemDescription::SetFinalValues(ComSafeArrayIn(BOOL, aEnabled),
- ComSafeArrayIn(IN_BSTR, argVboxValues),
+ ComSafeArrayIn(IN_BSTR, argVBoxValues),
ComSafeArrayIn(IN_BSTR, argExtraConfigValues))
{
#ifndef RT_OS_WINDOWS
@@ -1283,7 +1446,7 @@ STDMETHODIMP VirtualSystemDescription::SetFinalValues(ComSafeArrayIn(BOOL, aEnab
#endif /* RT_OS_WINDOWS */
CheckComArgSafeArrayNotNull(aEnabled);
- CheckComArgSafeArrayNotNull(argVboxValues);
+ CheckComArgSafeArrayNotNull(argVBoxValues);
CheckComArgSafeArrayNotNull(argExtraConfigValues);
AutoCaller autoCaller(this);
@@ -1292,11 +1455,11 @@ STDMETHODIMP VirtualSystemDescription::SetFinalValues(ComSafeArrayIn(BOOL, aEnab
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
com::SafeArray<BOOL> sfaEnabled(ComSafeArrayInArg(aEnabled));
- com::SafeArray<IN_BSTR> sfaVboxValues(ComSafeArrayInArg(argVboxValues));
+ com::SafeArray<IN_BSTR> sfaVBoxValues(ComSafeArrayInArg(argVBoxValues));
com::SafeArray<IN_BSTR> sfaExtraConfigValues(ComSafeArrayInArg(argExtraConfigValues));
if ( (sfaEnabled.size() != m->llDescriptions.size())
- || (sfaVboxValues.size() != m->llDescriptions.size())
+ || (sfaVBoxValues.size() != m->llDescriptions.size())
|| (sfaExtraConfigValues.size() != m->llDescriptions.size())
)
return E_INVALIDARG;
@@ -1311,7 +1474,7 @@ STDMETHODIMP VirtualSystemDescription::SetFinalValues(ComSafeArrayIn(BOOL, aEnab
if (sfaEnabled[i])
{
- vsde.strVboxCurrent = sfaVboxValues[i];
+ vsde.strVBoxCurrent = sfaVBoxValues[i];
vsde.strExtraConfigCurrent = sfaExtraConfigValues[i];
}
else
@@ -1326,7 +1489,7 @@ STDMETHODIMP VirtualSystemDescription::SetFinalValues(ComSafeArrayIn(BOOL, aEnab
* @return
*/
STDMETHODIMP VirtualSystemDescription::AddDescription(VirtualSystemDescriptionType_T aType,
- IN_BSTR aVboxValue,
+ IN_BSTR aVBoxValue,
IN_BSTR aExtraConfigValue)
{
AutoCaller autoCaller(this);
@@ -1334,7 +1497,7 @@ STDMETHODIMP VirtualSystemDescription::AddDescription(VirtualSystemDescriptionTy
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
- addEntry(aType, "", aVboxValue, aVboxValue, 0, aExtraConfigValue);
+ addEntry(aType, "", aVBoxValue, aVBoxValue, 0, aExtraConfigValue);
return S_OK;
}
@@ -1351,7 +1514,7 @@ STDMETHODIMP VirtualSystemDescription::AddDescription(VirtualSystemDescriptionTy
void VirtualSystemDescription::addEntry(VirtualSystemDescriptionType_T aType,
const Utf8Str &strRef,
const Utf8Str &aOvfValue,
- const Utf8Str &aVboxValue,
+ const Utf8Str &aVBoxValue,
uint32_t ulSizeMB,
const Utf8Str &strExtraConfig /*= ""*/)
{
@@ -1360,15 +1523,17 @@ void VirtualSystemDescription::addEntry(VirtualSystemDescriptionType_T aType,
vsde.type = aType;
vsde.strRef = strRef;
vsde.strOvf = aOvfValue;
- vsde.strVboxSuggested // remember original value
- = vsde.strVboxCurrent // and set current value which can be overridden by setFinalValues()
- = aVboxValue;
+ vsde.strVBoxSuggested // remember original value
+ = vsde.strVBoxCurrent // and set current value which can be overridden by setFinalValues()
+ = aVBoxValue;
vsde.strExtraConfigSuggested
= vsde.strExtraConfigCurrent
= strExtraConfig;
vsde.ulSizeMB = ulSizeMB;
+ vsde.skipIt = false;
m->llDescriptions.push_back(vsde);
+
}
/**
@@ -1394,6 +1559,26 @@ std::list<VirtualSystemDescriptionEntry*> VirtualSystemDescription::findByType(V
}
/**
+ * Private method; delete all records from the list
+ * m->llDescriptions that match the given type.
+ * @param aType
+ * @return
+ */
+void VirtualSystemDescription::removeByType(VirtualSystemDescriptionType_T aType)
+{
+ std::list<VirtualSystemDescriptionEntry*> vsd;
+
+ list<VirtualSystemDescriptionEntry>::iterator it = m->llDescriptions.begin();
+ while (it != m->llDescriptions.end())
+ {
+ if (it->type == aType)
+ it = m->llDescriptions.erase(it);
+ else
+ ++it;
+ }
+}
+
+/**
* Private method; looks thru the member hardware items for the IDE, SATA, or SCSI controller with
* the given reference ID. Useful when needing the controller for a particular
* virtual disk.
@@ -1437,7 +1622,7 @@ const VirtualSystemDescriptionEntry* VirtualSystemDescription::findControllerFro
* @param elmMachine <vbox:Machine> element with attributes and subelements from some
* DOM tree.
*/
-void VirtualSystemDescription::importVboxMachineXML(const xml::ElementNode &elmMachine)
+void VirtualSystemDescription::importVBoxMachineXML(const xml::ElementNode &elmMachine)
{
settings::MachineConfigFile *pConfig = NULL;
@@ -1459,7 +1644,7 @@ void VirtualSystemDescription::importVboxMachineXML(const xml::ElementNode &elmM
}
/**
- * Returns the machine config created by importVboxMachineXML() or NULL if there's none.
+ * Returns the machine config created by importVBoxMachineXML() or NULL if there's none.
* @return
*/
const settings::MachineConfigFile* VirtualSystemDescription::getMachineConfig() const
diff --git a/src/VBox/Main/src-server/ApplianceImplExport.cpp b/src/VBox/Main/src-server/ApplianceImplExport.cpp
index cc47b4d1..c8c5718f 100644
--- a/src/VBox/Main/src-server/ApplianceImplExport.cpp
+++ b/src/VBox/Main/src-server/ApplianceImplExport.cpp
@@ -1,11 +1,10 @@
/* $Id: ApplianceImplExport.cpp $ */
/** @file
- *
* IAppliance and IVirtualSystem COM class implementations.
*/
/*
- * Copyright (C) 2008-2011 Oracle Corporation
+ * Copyright (C) 2008-2014 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -57,7 +56,7 @@ using namespace std;
* @param appliance
* @return
*/
-STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualSystemDescription **aDescription)
+STDMETHODIMP Machine::ExportTo(IAppliance *aAppliance, IN_BSTR location, IVirtualSystemDescription **aDescription)
{
HRESULT rc = S_OK;
@@ -86,32 +85,32 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS
// store the machine object so we can dump the XML in Appliance::Write()
pNewDesc->m->pMachine = this;
- // now fill it with description items
- Bstr bstrName1;
- Bstr bstrDescription;
- Bstr bstrGuestOSType;
- uint32_t cCPUs;
- uint32_t ulMemSizeMB;
- BOOL fUSBEnabled;
- BOOL fAudioEnabled;
- AudioControllerType_T audioController;
+ // first, call the COM methods, as they request locks
+ BOOL fUSBEnabled = FALSE;
+ com::SafeIfaceArray<IUSBController> usbControllers;
+ rc = COMGETTER(USBControllers)(ComSafeArrayAsOutParam(usbControllers));
+ if (SUCCEEDED(rc))
+ {
+ for (unsigned i = 0; i < usbControllers.size(); i++)
+ {
+ USBControllerType_T enmType;
- ComPtr<IUSBController> pUsbController;
- ComPtr<IAudioAdapter> pAudioAdapter;
+ rc = usbControllers[i]->COMGETTER(Type)(&enmType);
+ if (FAILED(rc)) throw rc;
- // first, call the COM methods, as they request locks
- rc = COMGETTER(USBController)(pUsbController.asOutParam());
- if (FAILED(rc))
- fUSBEnabled = false;
- else
- rc = pUsbController->COMGETTER(Enabled)(&fUSBEnabled);
+ if (enmType == USBControllerType_OHCI)
+ fUSBEnabled = TRUE;
+ }
+ }
// request the machine lock while accessing internal members
AutoReadLock alock1(this COMMA_LOCKVAL_SRC_POS);
- pAudioAdapter = mAudioAdapter;
+ ComPtr<IAudioAdapter> pAudioAdapter = mAudioAdapter;
+ BOOL fAudioEnabled;
rc = pAudioAdapter->COMGETTER(Enabled)(&fAudioEnabled);
if (FAILED(rc)) throw rc;
+ AudioControllerType_T audioController;
rc = pAudioAdapter->COMGETTER(AudioController)(&audioController);
if (FAILED(rc)) throw rc;
@@ -122,9 +121,9 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS
// get guest OS
Utf8Str strOsTypeVBox = mUserData->s.strOsType;
// CPU count
- cCPUs = mHWData->mCPUCount;
+ uint32_t cCPUs = mHWData->mCPUCount;
// memory size in MB
- ulMemSizeMB = mHWData->mMemorySize;
+ uint32_t ulMemSizeMB = mHWData->mMemorySize;
// VRAM size?
// BIOS settings?
// 3D acceleration enabled?
@@ -132,11 +131,16 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS
// nested paging enabled?
// HWVirtExVPIDEnabled?
// PAEEnabled?
+ // Long mode enabled?
+ BOOL fLongMode;
+ rc = GetCPUProperty(CPUPropertyType_LongMode, &fLongMode);
+ if (FAILED(rc)) throw rc;
+
// snapshotFolder?
// VRDPServer?
/* Guest OS type */
- ovf::CIMOSType_T cim = convertVBoxOSType2CIMOSType(strOsTypeVBox.c_str());
+ ovf::CIMOSType_T cim = convertVBoxOSType2CIMOSType(strOsTypeVBox.c_str(), fLongMode);
pNewDesc->addEntry(VirtualSystemDescriptionType_OS,
"",
Utf8StrFmt("%RI32", cim),
@@ -206,41 +210,41 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS
// <const name="HardDiskControllerIDE" value="6" />
if (!pIDEController.isNull())
{
- Utf8Str strVbox;
+ Utf8Str strVBox;
StorageControllerType_T ctlr;
rc = pIDEController->COMGETTER(ControllerType)(&ctlr);
if (FAILED(rc)) throw rc;
switch(ctlr)
{
- case StorageControllerType_PIIX3: strVbox = "PIIX3"; break;
- case StorageControllerType_PIIX4: strVbox = "PIIX4"; break;
- case StorageControllerType_ICH6: strVbox = "ICH6"; break;
+ case StorageControllerType_PIIX3: strVBox = "PIIX3"; break;
+ case StorageControllerType_PIIX4: strVBox = "PIIX4"; break;
+ case StorageControllerType_ICH6: strVBox = "ICH6"; break;
}
- if (strVbox.length())
+ if (strVBox.length())
{
lIDEControllerPrimaryIndex = (int32_t)pNewDesc->m->llDescriptions.size();
pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerIDE,
Utf8StrFmt("%d", lIDEControllerPrimaryIndex), // strRef
- strVbox, // aOvfValue
- strVbox); // aVboxValue
+ strVBox, // aOvfValue
+ strVBox); // aVBoxValue
lIDEControllerSecondaryIndex = lIDEControllerPrimaryIndex + 1;
pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerIDE,
Utf8StrFmt("%d", lIDEControllerSecondaryIndex),
- strVbox,
- strVbox);
+ strVBox,
+ strVBox);
}
}
// <const name="HardDiskControllerSATA" value="7" />
if (!pSATAController.isNull())
{
- Utf8Str strVbox = "AHCI";
+ Utf8Str strVBox = "AHCI";
lSATAControllerIndex = (int32_t)pNewDesc->m->llDescriptions.size();
pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSATA,
Utf8StrFmt("%d", lSATAControllerIndex),
- strVbox,
- strVbox);
+ strVBox,
+ strVBox);
}
// <const name="HardDiskControllerSCSI" value="8" />
@@ -250,17 +254,17 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS
rc = pSCSIController->COMGETTER(ControllerType)(&ctlr);
if (SUCCEEDED(rc))
{
- Utf8Str strVbox = "LsiLogic"; // the default in VBox
+ Utf8Str strVBox = "LsiLogic"; // the default in VBox
switch(ctlr)
{
- case StorageControllerType_LsiLogic: strVbox = "LsiLogic"; break;
- case StorageControllerType_BusLogic: strVbox = "BusLogic"; break;
+ case StorageControllerType_LsiLogic: strVBox = "LsiLogic"; break;
+ case StorageControllerType_BusLogic: strVBox = "BusLogic"; break;
}
lSCSIControllerIndex = (int32_t)pNewDesc->m->llDescriptions.size();
pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSCSI,
Utf8StrFmt("%d", lSCSIControllerIndex),
- strVbox,
- strVbox);
+ strVBox,
+ strVBox);
}
else
throw rc;
@@ -270,12 +274,12 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS
{
// VirtualBox considers the SAS controller a class of its own but in OVF
// it should be a SCSI controller
- Utf8Str strVbox = "LsiLogicSas";
+ Utf8Str strVBox = "LsiLogicSas";
lSCSIControllerIndex = (int32_t)pNewDesc->m->llDescriptions.size();
pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSAS,
Utf8StrFmt("%d", lSCSIControllerIndex),
- strVbox,
- strVbox);
+ strVBox,
+ strVBox);
}
// <const name="HardDiskImage" value="9" />
@@ -320,15 +324,15 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS
rc = pHDA->COMGETTER(Device)(&lDevice);
if (FAILED(rc)) throw rc;
- Utf8Str strTargetVmdkName;
+ Utf8Str strTargetImageName;
Utf8Str strLocation;
LONG64 llSize = 0;
- if ( deviceType == DeviceType_HardDisk
- && pMedium
- )
+ if ( deviceType == DeviceType_HardDisk
+ && pMedium)
{
Bstr bstrLocation;
+
rc = pMedium->COMGETTER(Location)(bstrLocation.asOutParam());
if (FAILED(rc)) throw rc;
strLocation = bstrLocation;
@@ -343,12 +347,11 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS
// returns pMedium if there are no diff images
if (FAILED(rc)) throw rc;
- Bstr bstrBaseName;
- rc = pBaseMedium->COMGETTER(Name)(bstrBaseName.asOutParam());
- if (FAILED(rc)) throw rc;
-
- Utf8Str strTargetName = Utf8Str(locInfo.strPath).stripPath().stripExt();
- strTargetVmdkName = Utf8StrFmt("%s-disk%d.vmdk", strTargetName.c_str(), ++pAppliance->m->cDisks);
+ Utf8Str strName = Utf8Str(locInfo.strPath).stripPath().stripExt();
+ strTargetImageName = Utf8StrFmt("%s-disk%d.vmdk", strName.c_str(), ++pAppliance->m->cDisks);
+ if (strTargetImageName.length() > RTTAR_NAME_MAX)
+ throw setError(VBOX_E_NOT_SUPPORTED,
+ tr("Cannot attach disk '%s' -- file name too long"), strTargetImageName.c_str());
// force reading state, or else size will be returned as 0
MediumState_T ms;
@@ -358,7 +361,55 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS
rc = pBaseMedium->COMGETTER(Size)(&llSize);
if (FAILED(rc)) throw rc;
}
+ else if ( deviceType == DeviceType_DVD
+ && pMedium)
+ {
+ /*
+ * check the minimal rules to grant access to export an image
+ * 1. no host drive CD/DVD image
+ * 2. the image must be accessible and readable
+ * 3. only ISO image is exported
+ */
+
+ //1. no host drive CD/DVD image
+ BOOL fHostDrive = false;
+ rc = pMedium->COMGETTER(HostDrive)(&fHostDrive);
+ if (FAILED(rc)) throw rc;
+
+ if(fHostDrive)
+ continue;
+
+ //2. the image must be accessible and readable
+ MediumState_T ms;
+ rc = pMedium->RefreshState(&ms);
+ if (FAILED(rc)) throw rc;
+
+ if (ms != MediumState_Created)
+ continue;
+ //3. only ISO image is exported
+ Bstr bstrLocation;
+ rc = pMedium->COMGETTER(Location)(bstrLocation.asOutParam());
+ if (FAILED(rc)) throw rc;
+
+ strLocation = bstrLocation;
+
+ Utf8Str ext = strLocation;
+ ext.assignEx(RTPathExt(ext.c_str()));//returns extension with dot (".iso")
+
+ int eq = ext.compare(".iso", Utf8Str::CaseInsensitive);
+ if (eq != 0)
+ continue;
+
+ Utf8Str strName = Utf8Str(locInfo.strPath).stripPath().stripExt();
+ strTargetImageName = Utf8StrFmt("%s-disk%d.iso", strName.c_str(), ++pAppliance->m->cDisks);
+ if (strTargetImageName.length() > RTTAR_NAME_MAX)
+ throw setError(VBOX_E_NOT_SUPPORTED,
+ tr("Cannot attach image '%s' -- file name too long"), strTargetImageName.c_str());
+
+ rc = pMedium->COMGETTER(Size)(&llSize);
+ if (FAILED(rc)) throw rc;
+ }
// and how this translates to the virtual system
int32_t lControllerVsys = 0;
LONG lChannelVsys;
@@ -426,19 +477,20 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS
case DeviceType_HardDisk:
Log(("Adding VirtualSystemDescriptionType_HardDiskImage, disk size: %RI64\n", llSize));
pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskImage,
- strTargetVmdkName, // disk ID: let's use the name
- strTargetVmdkName, // OVF value:
+ strTargetImageName, // disk ID: let's use the name
+ strTargetImageName, // OVF value:
strLocation, // vbox value: media path
(uint32_t)(llSize / _1M),
strExtra);
break;
case DeviceType_DVD:
+ Log(("Adding VirtualSystemDescriptionType_CDROM, disk size: %RI64\n", llSize));
pNewDesc->addEntry(VirtualSystemDescriptionType_CDROM,
- strEmpty, // disk ID
- strEmpty, // OVF value
- strEmpty, // vbox value
- 1, // ulSize
+ strTargetImageName, // disk ID
+ strTargetImageName, // OVF value
+ strLocation, // vbox value
+ (uint32_t)(llSize / _1M),// ulSize
strExtra);
break;
@@ -525,11 +577,12 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS
/**
* Public method implementation.
* @param format
+ * @param options
* @param path
* @param aProgress
* @return
*/
-STDMETHODIMP Appliance::Write(IN_BSTR format, BOOL fManifest, IN_BSTR path, IProgress **aProgress)
+STDMETHODIMP Appliance::Write(IN_BSTR format, ComSafeArrayIn(ImportOptions_T, options), IN_BSTR path, IProgress **aProgress)
{
if (!path) return E_POINTER;
CheckComArgOutPointerValid(aProgress);
@@ -539,6 +592,31 @@ STDMETHODIMP Appliance::Write(IN_BSTR format, BOOL fManifest, IN_BSTR path, IPro
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+ if (options != NULL)
+ m->optListExport = com::SafeArray<ExportOptions_T>(ComSafeArrayInArg(options)).toList();
+
+// AssertReturn(!(m->optListExport.contains(ExportOptions_CreateManifest) && m->optListExport.contains(ExportOptions_ExportDVDImages)), E_INVALIDARG);
+
+ m->fExportISOImages = m->optListExport.contains(ExportOptions_ExportDVDImages);
+
+ if (!m->fExportISOImages)/* remove all ISO images from VirtualSystemDescription */
+ {
+ list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
+ for (it = m->virtualSystemDescriptions.begin();
+ it != m->virtualSystemDescriptions.end();
+ ++it)
+ {
+ ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
+ std::list<VirtualSystemDescriptionEntry*> skipped = vsdescThis->findByType(VirtualSystemDescriptionType_CDROM);
+ std::list<VirtualSystemDescriptionEntry*>:: iterator pItSkipped = skipped.begin();
+ while (pItSkipped != skipped.end())
+ {
+ (*pItSkipped)->skipIt = true;
+ ++pItSkipped;
+ }
+ }
+ }
+
// do not allow entering this method if the appliance is busy reading or writing
if (!isApplianceIdle())
return E_ACCESSDENIED;
@@ -550,21 +628,28 @@ STDMETHODIMP Appliance::Write(IN_BSTR format, BOOL fManifest, IN_BSTR path, IPro
return setError(VBOX_E_FILE_ERROR,
tr("Appliance file must have .ovf or .ova extension"));
- m->fManifest = !!fManifest;
+ m->fManifest = m->optListExport.contains(ExportOptions_CreateManifest);
Utf8Str strFormat(format);
- OVFFormat ovfF;
+
+ ovf::OVFVersion_T ovfF;
if (strFormat == "ovf-0.9")
- ovfF = OVF_0_9;
+ {
+ ovfF = ovf::OVFVersion_0_9;
+ }
else if (strFormat == "ovf-1.0")
- ovfF = OVF_1_0;
+ {
+ ovfF = ovf::OVFVersion_1_0;
+ }
else if (strFormat == "ovf-2.0")
- ovfF = OVF_2_0;
+ {
+ ovfF = ovf::OVFVersion_2_0;
+ }
else
return setError(VBOX_E_FILE_ERROR,
tr("Invalid format \"%s\" specified"), strFormat.c_str());
/* as of OVF 2.0 we have to use SHA256 */
- m->fSha256 = ovfF >= OVF_2_0;
+ m->fSha256 = ovfF >= ovf::OVFVersion_2_0;
ComObjPtr<Progress> progress;
HRESULT rc = S_OK;
@@ -614,7 +699,7 @@ STDMETHODIMP Appliance::Write(IN_BSTR format, BOOL fManifest, IN_BSTR path, IPro
* @param aProgress
* @return
*/
-HRESULT Appliance::writeImpl(OVFFormat aFormat, const LocationInfo &aLocInfo, ComObjPtr<Progress> &aProgress)
+HRESULT Appliance::writeImpl(ovf::OVFVersion_T aFormat, const LocationInfo &aLocInfo, ComObjPtr<Progress> &aProgress)
{
HRESULT rc = S_OK;
try
@@ -658,18 +743,30 @@ void Appliance::buildXML(AutoWriteLockBase& writeLock,
xml::Document &doc,
XMLStack &stack,
const Utf8Str &strPath,
- OVFFormat enFormat)
+ ovf::OVFVersion_T enFormat)
{
xml::ElementNode *pelmRoot = doc.createRootElement("Envelope");
- pelmRoot->setAttribute("ovf:version", enFormat == OVF_2_0 ? "2.0"
- : enFormat == OVF_1_0 ? "1.0"
+ pelmRoot->setAttribute("ovf:version", enFormat == ovf::OVFVersion_2_0 ? "2.0"
+ : enFormat == ovf::OVFVersion_1_0 ? "1.0"
: "0.9");
pelmRoot->setAttribute("xml:lang", "en-US");
- Utf8Str strNamespace = (enFormat == OVF_0_9)
- ? "http://www.vmware.com/schema/ovf/1/envelope" // 0.9
- : "http://schemas.dmtf.org/ovf/envelope/1"; // 1.0
+ Utf8Str strNamespace;
+
+ if (enFormat == ovf::OVFVersion_0_9)
+ {
+ strNamespace = ovf::OVF09_URI_string;
+ }
+ else if (enFormat == ovf::OVFVersion_1_0)
+ {
+ strNamespace = ovf::OVF10_URI_string;
+ }
+ else
+ {
+ strNamespace = ovf::OVF20_URI_string;
+ }
+
pelmRoot->setAttribute("xmlns", strNamespace);
pelmRoot->setAttribute("xmlns:ovf", strNamespace);
@@ -680,6 +777,14 @@ void Appliance::buildXML(AutoWriteLockBase& writeLock,
pelmRoot->setAttribute("xmlns:vbox", "http://www.virtualbox.org/ovf/machine");
// pelmRoot->setAttribute("xsi:schemaLocation", "http://schemas.dmtf.org/ovf/envelope/1 ../ovf-envelope.xsd");
+ if (enFormat == ovf::OVFVersion_2_0)
+ {
+ pelmRoot->setAttribute("xmlns:epasd",
+ "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_EthernetPortAllocationSettingData.xsd");
+ pelmRoot->setAttribute("xmlns:sasd",
+ "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_StorageAllocationSettingData.xsd");
+ }
+
// <Envelope>/<References>
xml::ElementNode *pelmReferences = pelmRoot->createChild("References"); // 0.9 and 1.0
@@ -689,7 +794,7 @@ void Appliance::buildXML(AutoWriteLockBase& writeLock,
<Disk ovf:capacity="4294967296" ovf:diskId="lamp" ovf:format="..." ovf:populatedSize="1924967692"/>
</DiskSection> */
xml::ElementNode *pelmDiskSection;
- if (enFormat == OVF_0_9)
+ if (enFormat == ovf::OVFVersion_0_9)
{
// <Section xsi:type="ovf:DiskSection_Type">
pelmDiskSection = pelmRoot->createChild("Section");
@@ -709,7 +814,7 @@ void Appliance::buildXML(AutoWriteLockBase& writeLock,
</Network>
</NetworkSection> */
xml::ElementNode *pelmNetworkSection;
- if (enFormat == OVF_0_9)
+ if (enFormat == ovf::OVFVersion_0_9)
{
// <Section xsi:type="ovf:NetworkSection_Type">
pelmNetworkSection = pelmRoot->createChild("Section");
@@ -729,7 +834,7 @@ void Appliance::buildXML(AutoWriteLockBase& writeLock,
xml::ElementNode *pelmToAddVirtualSystemsTo;
if (m->virtualSystemDescriptions.size() > 1)
{
- if (enFormat == OVF_0_9)
+ if (enFormat == ovf::OVFVersion_0_9)
throw setError(VBOX_E_FILE_ERROR,
tr("Cannot export more than one virtual system with OVF 0.9, use OVF 1.0"));
@@ -783,19 +888,46 @@ void Appliance::buildXML(AutoWriteLockBase& writeLock,
const VirtualSystemDescriptionEntry *pDiskEntry = itS->second;
// source path: where the VBox image is
- const Utf8Str &strSrcFilePath = pDiskEntry->strVboxCurrent;
+ const Utf8Str &strSrcFilePath = pDiskEntry->strVBoxCurrent;
Bstr bstrSrcFilePath(strSrcFilePath);
+ //skip empty Medium. There are no information to add into section <References> or <DiskSection>
+ if (strSrcFilePath.isEmpty() ||
+ pDiskEntry->skipIt == true)
+ continue;
+
// Do NOT check here whether the file exists. FindMedium will figure
// that out, and filesystem-based tests are simply wrong in the
// general case (think of iSCSI).
// We need some info from the source disks
ComPtr<IMedium> pSourceDisk;
+ //DeviceType_T deviceType = DeviceType_HardDisk;// by default
Log(("Finding source disk \"%ls\"\n", bstrSrcFilePath.raw()));
- HRESULT rc = mVirtualBox->OpenMedium(bstrSrcFilePath.raw(), DeviceType_HardDisk, AccessMode_ReadWrite, FALSE /* fForceNewUuid */, pSourceDisk.asOutParam());
- if (FAILED(rc)) throw rc;
+
+ HRESULT rc;
+
+ if (pDiskEntry->type == VirtualSystemDescriptionType_HardDiskImage)
+ {
+ rc = mVirtualBox->OpenMedium(bstrSrcFilePath.raw(),
+ DeviceType_HardDisk,
+ AccessMode_ReadWrite,
+ FALSE /* fForceNewUuid */,
+ pSourceDisk.asOutParam());
+ if (FAILED(rc))
+ throw rc;
+ }
+ else if (pDiskEntry->type == VirtualSystemDescriptionType_CDROM)//may be, this is CD/DVD
+ {
+ rc = mVirtualBox->OpenMedium(bstrSrcFilePath.raw(),
+ DeviceType_DVD,
+ AccessMode_ReadOnly,
+ FALSE,
+ pSourceDisk.asOutParam());
+ if (FAILED(rc))
+ throw rc;
+ }
Bstr uuidSource;
rc = pSourceDisk->COMGETTER(Id)(uuidSource.asOutParam());
@@ -811,7 +943,7 @@ void Appliance::buildXML(AutoWriteLockBase& writeLock,
strTargetFilePath.append(strTargetFileNameOnly);
// We are always exporting to VMDK stream optimized for now
- Bstr bstrSrcFormat = L"VMDK";
+ //Bstr bstrSrcFormat = L"VMDK";//not used
diskList.push_back(strTargetFilePath);
@@ -843,12 +975,22 @@ void Appliance::buildXML(AutoWriteLockBase& writeLock,
pelmDisk->setAttribute("ovf:capacity", Utf8StrFmt("%RI64", cbCapacity).c_str());
pelmDisk->setAttribute("ovf:diskId", strDiskID);
pelmDisk->setAttribute("ovf:fileRef", strFileRef);
- pelmDisk->setAttribute("ovf:format",
- (enFormat == OVF_0_9)
- ? "http://www.vmware.com/specifications/vmdk.html#sparse" // must be sparse or ovftool chokes
- : "http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized"
- // correct string as communicated to us by VMware (public bug #6612)
- );
+
+ if (pDiskEntry->type == VirtualSystemDescriptionType_HardDiskImage)//deviceType == DeviceType_HardDisk
+ {
+ pelmDisk->setAttribute("ovf:format",
+ (enFormat == ovf::OVFVersion_0_9)
+ ? "http://www.vmware.com/specifications/vmdk.html#sparse" // must be sparse or ovftool ch
+ : "http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized"
+ // correct string as communicated to us by VMware (public bug #6612)
+ );
+ }
+ else //pDiskEntry->type == VirtualSystemDescriptionType_CDROM, deviceType == DeviceType_DVD
+ {
+ pelmDisk->setAttribute("ovf:format",
+ "http://www.ecma-international.org/publications/standards/Ecma-119.htm"
+ );
+ }
// add the UUID of the newly target image to the OVF disk element, but in the
// vbox: namespace since it's not part of the standard
@@ -891,13 +1033,13 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
xml::ElementNode &elmToAddVirtualSystemsTo,
std::list<xml::ElementNode*> *pllElementsWithUuidAttributes,
ComObjPtr<VirtualSystemDescription> &vsdescThis,
- OVFFormat enFormat,
+ ovf::OVFVersion_T enFormat,
XMLStack &stack)
{
LogFlowFunc(("ENTER appliance %p\n", this));
xml::ElementNode *pelmVirtualSystem;
- if (enFormat == OVF_0_9)
+ if (enFormat == ovf::OVFVersion_0_9)
{
// <Section xsi:type="ovf:NetworkSection_Type">
pelmVirtualSystem = elmToAddVirtualSystemsTo.createChild("Content");
@@ -909,10 +1051,9 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
/*xml::ElementNode *pelmVirtualSystemInfo =*/ pelmVirtualSystem->createChild("Info")->addContent("A virtual machine");
std::list<VirtualSystemDescriptionEntry*> llName = vsdescThis->findByType(VirtualSystemDescriptionType_Name);
- if (llName.size() != 1)
- throw setError(VBOX_E_NOT_SUPPORTED,
- tr("Missing VM name"));
- Utf8Str &strVMName = llName.front()->strVboxCurrent;
+ if (!llName.size())
+ throw setError(VBOX_E_NOT_SUPPORTED, tr("Missing VM name"));
+ Utf8Str &strVMName = llName.back()->strVBoxCurrent;
pelmVirtualSystem->setAttribute("ovf:id", strVMName);
// product info
@@ -921,11 +1062,11 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
std::list<VirtualSystemDescriptionEntry*> llVendor = vsdescThis->findByType(VirtualSystemDescriptionType_Vendor);
std::list<VirtualSystemDescriptionEntry*> llVendorUrl = vsdescThis->findByType(VirtualSystemDescriptionType_VendorUrl);
std::list<VirtualSystemDescriptionEntry*> llVersion = vsdescThis->findByType(VirtualSystemDescriptionType_Version);
- bool fProduct = llProduct.size() && !llProduct.front()->strVboxCurrent.isEmpty();
- bool fProductUrl = llProductUrl.size() && !llProductUrl.front()->strVboxCurrent.isEmpty();
- bool fVendor = llVendor.size() && !llVendor.front()->strVboxCurrent.isEmpty();
- bool fVendorUrl = llVendorUrl.size() && !llVendorUrl.front()->strVboxCurrent.isEmpty();
- bool fVersion = llVersion.size() && !llVersion.front()->strVboxCurrent.isEmpty();
+ bool fProduct = llProduct.size() && !llProduct.back()->strVBoxCurrent.isEmpty();
+ bool fProductUrl = llProductUrl.size() && !llProductUrl.back()->strVBoxCurrent.isEmpty();
+ bool fVendor = llVendor.size() && !llVendor.back()->strVBoxCurrent.isEmpty();
+ bool fVendorUrl = llVendorUrl.size() && !llVendorUrl.back()->strVBoxCurrent.isEmpty();
+ bool fVersion = llVersion.size() && !llVersion.back()->strVBoxCurrent.isEmpty();
if (fProduct ||
fProductUrl ||
fVersion ||
@@ -941,7 +1082,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
<VendorUrl>http://www.sun.com</VendorUrl>
</Section> */
xml::ElementNode *pelmAnnotationSection;
- if (enFormat == OVF_0_9)
+ if (enFormat == ovf::OVFVersion_0_9)
{
// <Section ovf:required="false" xsi:type="ovf:ProductSection_Type">
pelmAnnotationSection = pelmVirtualSystem->createChild("Section");
@@ -952,28 +1093,28 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
pelmAnnotationSection->createChild("Info")->addContent("Meta-information about the installed software");
if (fProduct)
- pelmAnnotationSection->createChild("Product")->addContent(llProduct.front()->strVboxCurrent);
+ pelmAnnotationSection->createChild("Product")->addContent(llProduct.back()->strVBoxCurrent);
if (fVendor)
- pelmAnnotationSection->createChild("Vendor")->addContent(llVendor.front()->strVboxCurrent);
+ pelmAnnotationSection->createChild("Vendor")->addContent(llVendor.back()->strVBoxCurrent);
if (fVersion)
- pelmAnnotationSection->createChild("Version")->addContent(llVersion.front()->strVboxCurrent);
+ pelmAnnotationSection->createChild("Version")->addContent(llVersion.back()->strVBoxCurrent);
if (fProductUrl)
- pelmAnnotationSection->createChild("ProductUrl")->addContent(llProductUrl.front()->strVboxCurrent);
+ pelmAnnotationSection->createChild("ProductUrl")->addContent(llProductUrl.back()->strVBoxCurrent);
if (fVendorUrl)
- pelmAnnotationSection->createChild("VendorUrl")->addContent(llVendorUrl.front()->strVboxCurrent);
+ pelmAnnotationSection->createChild("VendorUrl")->addContent(llVendorUrl.back()->strVBoxCurrent);
}
// description
std::list<VirtualSystemDescriptionEntry*> llDescription = vsdescThis->findByType(VirtualSystemDescriptionType_Description);
if (llDescription.size() &&
- !llDescription.front()->strVboxCurrent.isEmpty())
+ !llDescription.back()->strVBoxCurrent.isEmpty())
{
/* <Section ovf:required="false" xsi:type="ovf:AnnotationSection_Type">
<Info>A human-readable annotation</Info>
<Annotation>Plan 9</Annotation>
</Section> */
xml::ElementNode *pelmAnnotationSection;
- if (enFormat == OVF_0_9)
+ if (enFormat == ovf::OVFVersion_0_9)
{
// <Section ovf:required="false" xsi:type="ovf:AnnotationSection_Type">
pelmAnnotationSection = pelmVirtualSystem->createChild("Section");
@@ -983,20 +1124,20 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
pelmAnnotationSection = pelmVirtualSystem->createChild("AnnotationSection");
pelmAnnotationSection->createChild("Info")->addContent("A human-readable annotation");
- pelmAnnotationSection->createChild("Annotation")->addContent(llDescription.front()->strVboxCurrent);
+ pelmAnnotationSection->createChild("Annotation")->addContent(llDescription.back()->strVBoxCurrent);
}
// license
std::list<VirtualSystemDescriptionEntry*> llLicense = vsdescThis->findByType(VirtualSystemDescriptionType_License);
if (llLicense.size() &&
- !llLicense.front()->strVboxCurrent.isEmpty())
+ !llLicense.back()->strVBoxCurrent.isEmpty())
{
/* <EulaSection>
<Info ovf:msgid="6">License agreement for the Virtual System.</Info>
<License ovf:msgid="1">License terms can go in here.</License>
</EulaSection> */
xml::ElementNode *pelmEulaSection;
- if (enFormat == OVF_0_9)
+ if (enFormat == ovf::OVFVersion_0_9)
{
pelmEulaSection = pelmVirtualSystem->createChild("Section");
pelmEulaSection->setAttribute("xsi:type", "ovf:EulaSection_Type");
@@ -1005,21 +1146,20 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
pelmEulaSection = pelmVirtualSystem->createChild("EulaSection");
pelmEulaSection->createChild("Info")->addContent("License agreement for the virtual system");
- pelmEulaSection->createChild("License")->addContent(llLicense.front()->strVboxCurrent);
+ pelmEulaSection->createChild("License")->addContent(llLicense.back()->strVBoxCurrent);
}
// operating system
std::list<VirtualSystemDescriptionEntry*> llOS = vsdescThis->findByType(VirtualSystemDescriptionType_OS);
- if (llOS.size() != 1)
- throw setError(VBOX_E_NOT_SUPPORTED,
- tr("Missing OS type"));
+ if (!llOS.size())
+ throw setError(VBOX_E_NOT_SUPPORTED, tr("Missing OS type"));
/* <OperatingSystemSection ovf:id="82">
<Info>Guest Operating System</Info>
<Description>Linux 2.6.x</Description>
</OperatingSystemSection> */
- VirtualSystemDescriptionEntry *pvsdeOS = llOS.front();
+ VirtualSystemDescriptionEntry *pvsdeOS = llOS.back();
xml::ElementNode *pelmOperatingSystemSection;
- if (enFormat == OVF_0_9)
+ if (enFormat == ovf::OVFVersion_0_9)
{
pelmOperatingSystemSection = pelmVirtualSystem->createChild("Section");
pelmOperatingSystemSection->setAttribute("xsi:type", "ovf:OperatingSystemSection_Type");
@@ -1035,11 +1175,11 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
// add the VirtualBox ostype in a custom tag in a different namespace
xml::ElementNode *pelmVBoxOSType = pelmOperatingSystemSection->createChild("vbox:OSType");
pelmVBoxOSType->setAttribute("ovf:required", "false");
- pelmVBoxOSType->addContent(pvsdeOS->strVboxCurrent);
+ pelmVBoxOSType->addContent(pvsdeOS->strVBoxCurrent);
// <VirtualHardwareSection ovf:id="hw1" ovf:transport="iso">
xml::ElementNode *pelmVirtualHardwareSection;
- if (enFormat == OVF_0_9)
+ if (enFormat == ovf::OVFVersion_0_9)
{
// <Section xsi:type="ovf:VirtualHardwareSection_Type">
pelmVirtualHardwareSection = pelmVirtualSystem->createChild("Section");
@@ -1062,7 +1202,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
pelmSystem->createChild("vssd:ElementName")->addContent("Virtual Hardware Family"); // required OVF 1.0
// <vssd:InstanceId>0</vssd:InstanceId>
- if (enFormat == OVF_0_9)
+ if (enFormat == ovf::OVFVersion_0_9)
pelmSystem->createChild("vssd:InstanceId")->addContent("0");
else // capitalization changed...
pelmSystem->createChild("vssd:InstanceID")->addContent("0");
@@ -1071,7 +1211,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
pelmSystem->createChild("vssd:VirtualSystemIdentifier")->addContent(strVMName);
// <vssd:VirtualSystemType>vmx-4</vssd:VirtualSystemType>
const char *pcszHardware = "virtualbox-2.2";
- if (enFormat == OVF_0_9)
+ if (enFormat == ovf::OVFVersion_0_9)
// pretend to be vmware compatible then
pcszHardware = "vmx-6";
pelmSystem->createChild("vssd:VirtualSystemType")->addContent(pcszHardware);
@@ -1105,7 +1245,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
{
const VirtualSystemDescriptionEntry &desc = *itD;
- LogFlowFunc(("Loop %u: handling description entry ulIndex=%u, type=%s, strRef=%s, strOvf=%s, strVbox=%s, strExtraConfig=%s\n",
+ LogFlowFunc(("Loop %u: handling description entry ulIndex=%u, type=%s, strRef=%s, strOvf=%s, strVBox=%s, strExtraConfig=%s\n",
uLoop,
desc.ulIndex,
( desc.type == VirtualSystemDescriptionType_HardDiskControllerIDE ? "HardDiskControllerIDE"
@@ -1116,7 +1256,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
: Utf8StrFmt("%d", desc.type).c_str()),
desc.strRef.c_str(),
desc.strOvf.c_str(),
- desc.strVboxCurrent.c_str(),
+ desc.strVBoxCurrent.c_str(),
desc.strExtraConfigCurrent.c_str()));
ovf::ResourceType_T type = (ovf::ResourceType_T)0; // if this becomes != 0 then we do stuff
@@ -1140,6 +1280,10 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
uint64_t uTemp;
+ ovf::VirtualHardwareItem vhi;
+ ovf::StorageItem si;
+ ovf::EthernetPortItem epi;
+
switch (desc.type)
{
case VirtualSystemDescriptionType_CPU:
@@ -1155,7 +1299,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
{
strDescription = "Number of virtual CPUs";
type = ovf::ResourceType_Processor; // 3
- desc.strVboxCurrent.toInt(uTemp);
+ desc.strVBoxCurrent.toInt(uTemp);
lVirtualQuantity = (int32_t)uTemp;
strCaption = Utf8StrFmt("%d virtual CPU", lVirtualQuantity); // without this ovftool won't eat the item
}
@@ -1175,7 +1319,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
{
strDescription = "Memory Size";
type = ovf::ResourceType_Memory; // 4
- desc.strVboxCurrent.toInt(uTemp);
+ desc.strVBoxCurrent.toInt(uTemp);
lVirtualQuantity = (int32_t)(uTemp / _1M);
strAllocationUnits = "MegaBytes";
strCaption = Utf8StrFmt("%d MB of memory", lVirtualQuantity); // without this ovftool won't eat the item
@@ -1195,7 +1339,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
{
strDescription = "IDE Controller";
type = ovf::ResourceType_IDEController; // 5
- strResourceSubType = desc.strVboxCurrent;
+ strResourceSubType = desc.strVBoxCurrent;
if (!lIDEPrimaryControllerIndex)
{
@@ -1241,13 +1385,13 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
lAddress = 0;
lBusNumber = 0;
- if ( desc.strVboxCurrent.isEmpty() // AHCI is the default in VirtualBox
- || (!desc.strVboxCurrent.compare("ahci", Utf8Str::CaseInsensitive))
+ if ( desc.strVBoxCurrent.isEmpty() // AHCI is the default in VirtualBox
+ || (!desc.strVBoxCurrent.compare("ahci", Utf8Str::CaseInsensitive))
)
strResourceSubType = "AHCI";
else
throw setError(VBOX_E_NOT_SUPPORTED,
- tr("Invalid config string \"%s\" in SATA controller"), desc.strVboxCurrent.c_str());
+ tr("Invalid config string \"%s\" in SATA controller"), desc.strVBoxCurrent.c_str());
// remember this ID
idSATAController = ulInstanceID;
@@ -1277,17 +1421,17 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
lAddress = 0;
lBusNumber = 0;
- if ( desc.strVboxCurrent.isEmpty() // LsiLogic is the default in VirtualBox
- || (!desc.strVboxCurrent.compare("lsilogic", Utf8Str::CaseInsensitive))
+ if ( desc.strVBoxCurrent.isEmpty() // LsiLogic is the default in VirtualBox
+ || (!desc.strVBoxCurrent.compare("lsilogic", Utf8Str::CaseInsensitive))
)
strResourceSubType = "lsilogic";
- else if (!desc.strVboxCurrent.compare("buslogic", Utf8Str::CaseInsensitive))
+ else if (!desc.strVBoxCurrent.compare("buslogic", Utf8Str::CaseInsensitive))
strResourceSubType = "buslogic";
- else if (!desc.strVboxCurrent.compare("lsilogicsas", Utf8Str::CaseInsensitive))
+ else if (!desc.strVBoxCurrent.compare("lsilogicsas", Utf8Str::CaseInsensitive))
strResourceSubType = "lsilogicsas";
else
throw setError(VBOX_E_NOT_SUPPORTED,
- tr("Invalid config string \"%s\" in SCSI/SAS controller"), desc.strVboxCurrent.c_str());
+ tr("Invalid config string \"%s\" in SCSI/SAS controller"), desc.strVBoxCurrent.c_str());
// remember this ID
idSCSIController = ulInstanceID;
@@ -1360,13 +1504,32 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
break;
case VirtualSystemDescriptionType_CDROM:
+ /* <Item>
+ <rasd:Caption>cdrom1</rasd:Caption>
+ <rasd:InstanceId>8</rasd:InstanceId>
+ <rasd:ResourceType>15</rasd:ResourceType>
+ <rasd:HostResource>/disk/cdrom1</rasd:HostResource>
+ <rasd:Parent>4</rasd:Parent>
+ <rasd:AddressOnParent>0</rasd:AddressOnParent>
+ </Item> */
if (uLoop == 2)
{
+ //uint32_t cDisks = stack.mapDisks.size();
+ Utf8Str strDiskID = Utf8StrFmt("iso%RI32", ++cDVDs);
+
strDescription = "CD-ROM Drive";
- strCaption = Utf8StrFmt("cdrom%RI32", ++cDVDs); // OVFTool starts with 1
+ strCaption = Utf8StrFmt("cdrom%RI32", cDVDs); // OVFTool starts with 1
type = ovf::ResourceType_CDDrive; // 15
lAutomaticAllocation = 1;
+ //skip empty Medium. There are no information to add into section <References> or <DiskSection>
+ if (desc.strVBoxCurrent.isNotEmpty() &&
+ desc.skipIt == false)
+ {
+ // the following references the "<Disks>" XML block
+ strHostResource = Utf8StrFmt("/disk/%s", strDiskID.c_str());
+ }
+
// controller=<index>;channel=<c>
size_t pos1 = desc.strExtraConfigCurrent.find("controller=");
size_t pos2 = desc.strExtraConfigCurrent.find("channel=");
@@ -1395,6 +1558,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
throw setError(VBOX_E_NOT_SUPPORTED,
tr("Missing or bad extra config string in DVD drive medium: \"%s\""), desc.strExtraConfigCurrent.c_str());
+ stack.mapDisks[strDiskID] = &desc;
// there is no DVD drive map to update because it is
// handled completely with this entry.
}
@@ -1409,7 +1573,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
<rasd:InstanceID>3</rasd:InstanceID>
<rasd:ResourceType>10</rasd:ResourceType>
</Item> */
- if (uLoop == 1)
+ if (uLoop == 2)
{
lAutomaticAllocation = 1;
strCaption = Utf8StrFmt("Ethernet adapter on '%s'", desc.strOvf.c_str());
@@ -1418,7 +1582,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
* To be compatible with vmware & others we set
* PCNet32 for our PCNet types & E1000 for the
* E1000 cards. */
- switch (desc.strVboxCurrent.toInt32())
+ switch (desc.strVBoxCurrent.toInt32())
{
case NetworkAdapterType_Am79C970A:
case NetworkAdapterType_Am79C973: strResourceSubType = "PCNet32"; break;
@@ -1478,65 +1642,176 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
if (type)
{
xml::ElementNode *pItem;
+ xml::ElementNode *pItemHelper;
+ RTCString itemElement;
+ RTCString itemElementHelper;
- pItem = pelmVirtualHardwareSection->createChild("Item");
+ if (enFormat == ovf::OVFVersion_2_0)
+ {
+ if(uLoop == 2)
+ {
+ if (desc.type == VirtualSystemDescriptionType_NetworkAdapter)
+ {
+ itemElement = "epasd:";
+ pItem = pelmVirtualHardwareSection->createChild("EthernetPortItem");
+ }
+ else if (desc.type == VirtualSystemDescriptionType_CDROM ||
+ desc.type == VirtualSystemDescriptionType_HardDiskImage)
+ {
+ itemElement = "sasd:";
+ pItem = pelmVirtualHardwareSection->createChild("StorageItem");
+ }
+ else
+ pItem = NULL;
+ }
+ else
+ {
+ itemElement = "rasd:";
+ pItem = pelmVirtualHardwareSection->createChild("Item");
+ }
+ }
+ else
+ {
+ itemElement = "rasd:";
+ pItem = pelmVirtualHardwareSection->createChild("Item");
+ }
// NOTE: DO NOT CHANGE THE ORDER of these items! The OVF standards prescribes that
// the elements from the rasd: namespace must be sorted by letter, and VMware
// actually requires this as well (see public bug #6612)
if (lAddress != -1)
- pItem->createChild("rasd:Address")->addContent(Utf8StrFmt("%d", lAddress));
+ {
+ //pItem->createChild("rasd:Address")->addContent(Utf8StrFmt("%d", lAddress));
+ itemElementHelper = itemElement;
+ pItemHelper = pItem->createChild(itemElementHelper.append("Address").c_str());
+ pItemHelper->addContent(Utf8StrFmt("%d", lAddress));
+ }
if (lAddressOnParent != -1)
- pItem->createChild("rasd:AddressOnParent")->addContent(Utf8StrFmt("%d", lAddressOnParent));
+ {
+ //pItem->createChild("rasd:AddressOnParent")->addContent(Utf8StrFmt("%d", lAddressOnParent));
+ itemElementHelper = itemElement;
+ pItemHelper = pItem->createChild(itemElementHelper.append("AddressOnParent").c_str());
+ pItemHelper->addContent(Utf8StrFmt("%d", lAddressOnParent));
+ }
if (!strAllocationUnits.isEmpty())
- pItem->createChild("rasd:AllocationUnits")->addContent(strAllocationUnits);
+ {
+ //pItem->createChild("rasd:AllocationUnits")->addContent(strAllocationUnits);
+ itemElementHelper = itemElement;
+ pItemHelper = pItem->createChild(itemElementHelper.append("AllocationUnits").c_str());
+ pItemHelper->addContent(strAllocationUnits);
+ }
if (lAutomaticAllocation != -1)
- pItem->createChild("rasd:AutomaticAllocation")->addContent( (lAutomaticAllocation) ? "true" : "false" );
+ {
+ //pItem->createChild("rasd:AutomaticAllocation")->addContent( (lAutomaticAllocation) ? "true" : "false" );
+ itemElementHelper = itemElement;
+ pItemHelper = pItem->createChild(itemElementHelper.append("AutomaticAllocation").c_str());
+ pItemHelper->addContent((lAutomaticAllocation) ? "true" : "false" );
+ }
if (lBusNumber != -1)
- if (enFormat == OVF_0_9) // BusNumber is invalid OVF 1.0 so only write it in 0.9 mode for OVFTool compatibility
- pItem->createChild("rasd:BusNumber")->addContent(Utf8StrFmt("%d", lBusNumber));
+ {
+ if (enFormat == ovf::OVFVersion_0_9)
+ {
+ // BusNumber is invalid OVF 1.0 so only write it in 0.9 mode for OVFTool
+ //pItem->createChild("rasd:BusNumber")->addContent(Utf8StrFmt("%d", lBusNumber));
+ itemElementHelper = itemElement;
+ pItemHelper = pItem->createChild(itemElementHelper.append("BusNumber").c_str());
+ pItemHelper->addContent(Utf8StrFmt("%d", lBusNumber));
+ }
+ }
if (!strCaption.isEmpty())
- pItem->createChild("rasd:Caption")->addContent(strCaption);
+ {
+ //pItem->createChild("rasd:Caption")->addContent(strCaption);
+ itemElementHelper = itemElement;
+ pItemHelper = pItem->createChild(itemElementHelper.append("Caption").c_str());
+ pItemHelper->addContent(strCaption);
+ }
if (!strConnection.isEmpty())
- pItem->createChild("rasd:Connection")->addContent(strConnection);
+ {
+ //pItem->createChild("rasd:Connection")->addContent(strConnection);
+ itemElementHelper = itemElement;
+ pItemHelper = pItem->createChild(itemElementHelper.append("Connection").c_str());
+ pItemHelper->addContent(strConnection);
+ }
if (!strDescription.isEmpty())
- pItem->createChild("rasd:Description")->addContent(strDescription);
+ {
+ //pItem->createChild("rasd:Description")->addContent(strDescription);
+ itemElementHelper = itemElement;
+ pItemHelper = pItem->createChild(itemElementHelper.append("Description").c_str());
+ pItemHelper->addContent(strDescription);
+ }
if (!strCaption.isEmpty())
- if (enFormat == OVF_1_0)
- pItem->createChild("rasd:ElementName")->addContent(strCaption);
+ {
+ if (enFormat == ovf::OVFVersion_1_0)
+ {
+ //pItem->createChild("rasd:ElementName")->addContent(strCaption);
+ itemElementHelper = itemElement;
+ pItemHelper = pItem->createChild(itemElementHelper.append("ElementName").c_str());
+ pItemHelper->addContent(strCaption);
+ }
+ }
if (!strHostResource.isEmpty())
- pItem->createChild("rasd:HostResource")->addContent(strHostResource);
+ {
+ //pItem->createChild("rasd:HostResource")->addContent(strHostResource);
+ itemElementHelper = itemElement;
+ pItemHelper = pItem->createChild(itemElementHelper.append("HostResource").c_str());
+ pItemHelper->addContent(strHostResource);
+ }
- // <rasd:InstanceID>1</rasd:InstanceID>
- xml::ElementNode *pelmInstanceID;
- if (enFormat == OVF_0_9)
- pelmInstanceID = pItem->createChild("rasd:InstanceId");
- else
- pelmInstanceID = pItem->createChild("rasd:InstanceID"); // capitalization changed...
- pelmInstanceID->addContent(Utf8StrFmt("%d", ulInstanceID++));
+ {
+ // <rasd:InstanceID>1</rasd:InstanceID>
+ itemElementHelper = itemElement;
+ if (enFormat == ovf::OVFVersion_0_9)
+ //pelmInstanceID = pItem->createChild("rasd:InstanceId");
+ pItemHelper = pItem->createChild(itemElementHelper.append("InstanceId").c_str());
+ else
+ //pelmInstanceID = pItem->createChild("rasd:InstanceID"); // capitalization changed...
+ pItemHelper = pItem->createChild(itemElementHelper.append("InstanceID").c_str());
+
+ pItemHelper->addContent(Utf8StrFmt("%d", ulInstanceID++));
+ }
if (ulParent)
- pItem->createChild("rasd:Parent")->addContent(Utf8StrFmt("%d", ulParent));
+ {
+ //pItem->createChild("rasd:Parent")->addContent(Utf8StrFmt("%d", ulParent));
+ itemElementHelper = itemElement;
+ pItemHelper = pItem->createChild(itemElementHelper.append("Parent").c_str());
+ pItemHelper->addContent(Utf8StrFmt("%d", ulParent));
+ }
if (!strResourceSubType.isEmpty())
- pItem->createChild("rasd:ResourceSubType")->addContent(strResourceSubType);
+ {
+ //pItem->createChild("rasd:ResourceSubType")->addContent(strResourceSubType);
+ itemElementHelper = itemElement;
+ pItemHelper = pItem->createChild(itemElementHelper.append("ResourceSubType").c_str());
+ pItemHelper->addContent(strResourceSubType);
+ }
- // <rasd:ResourceType>3</rasd:ResourceType>
- pItem->createChild("rasd:ResourceType")->addContent(Utf8StrFmt("%d", type));
+ {
+ // <rasd:ResourceType>3</rasd:ResourceType>
+ //pItem->createChild("rasd:ResourceType")->addContent(Utf8StrFmt("%d", type));
+ itemElementHelper = itemElement;
+ pItemHelper = pItem->createChild(itemElementHelper.append("ResourceType").c_str());
+ pItemHelper->addContent(Utf8StrFmt("%d", type));
+ }
// <rasd:VirtualQuantity>1</rasd:VirtualQuantity>
if (lVirtualQuantity != -1)
- pItem->createChild("rasd:VirtualQuantity")->addContent(Utf8StrFmt("%d", lVirtualQuantity));
+ {
+ //pItem->createChild("rasd:VirtualQuantity")->addContent(Utf8StrFmt("%d", lVirtualQuantity));
+ itemElementHelper = itemElement;
+ pItemHelper = pItem->createChild(itemElementHelper.append("VirtualQuantity").c_str());
+ pItemHelper->addContent(Utf8StrFmt("%d", lVirtualQuantity));
+ }
}
}
} // for (size_t uLoop = 1; uLoop <= 2; ++uLoop)
@@ -1558,10 +1833,26 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
AutoWriteLock machineLock(vsdescThis->m->pMachine COMMA_LOCKVAL_SRC_POS);
// fill the machine config
vsdescThis->m->pMachine->copyMachineDataToSettings(*pConfig);
+
+ // Apply export tweaks to machine settings
+ bool fStripAllMACs = m->optListExport.contains(ExportOptions_StripAllMACs);
+ bool fStripAllNonNATMACs = m->optListExport.contains(ExportOptions_StripAllNonNATMACs);
+ if (fStripAllMACs || fStripAllNonNATMACs)
+ {
+ for (settings::NetworkAdaptersList::iterator it = pConfig->hardwareMachine.llNetworkAdapters.begin();
+ it != pConfig->hardwareMachine.llNetworkAdapters.end();
+ ++it)
+ {
+ settings::NetworkAdapter &nic = *it;
+ if (fStripAllMACs || (fStripAllNonNATMACs && nic.mode != NetworkAttachmentType_NAT))
+ nic.strMACAddress.setNull();
+ }
+ }
+
// write the machine config to the vbox:Machine element
pConfig->buildMachineXML(*pelmVBoxMachine,
- settings::MachineConfigFile::BuildMachineXML_WriteVboxVersionAttribute
- | settings::MachineConfigFile::BuildMachineXML_SkipRemovableMedia
+ settings::MachineConfigFile::BuildMachineXML_WriteVBoxVersionAttribute
+ /*| settings::MachineConfigFile::BuildMachineXML_SkipRemovableMedia*/
| settings::MachineConfigFile::BuildMachineXML_SuppressSavedState,
// but not BuildMachineXML_IncludeSnapshots nor BuildMachineXML_MediaRegistry
pllElementsWithUuidAttributes);
@@ -1648,7 +1939,11 @@ HRESULT Appliance::writeFSOVF(TaskOVF *pTask, AutoWriteLockBase& writeLock)
RT_ZERO(storage);
storage.fCreateDigest = m->fManifest;
storage.fSha256 = m->fSha256;
- int vrc = VDInterfaceAdd(&pFileIo->Core, "Appliance::IOFile",
+
+
+ Utf8Str name = applianceIOName(applianceIOFile);
+
+ int vrc = VDInterfaceAdd(&pFileIo->Core, name.c_str(),
VDINTERFACETYPE_IO, 0, sizeof(VDINTERFACEIO),
&storage.pVDImageIfaces);
if (RT_FAILURE(vrc))
@@ -1657,7 +1952,7 @@ HRESULT Appliance::writeFSOVF(TaskOVF *pTask, AutoWriteLockBase& writeLock)
break;
}
rc = writeFSImpl(pTask, writeLock, pShaIo, &storage);
- }while(0);
+ } while (0);
/* Cleanup */
if (pShaIo)
@@ -1702,16 +1997,20 @@ HRESULT Appliance::writeFSOVA(TaskOVF *pTask, AutoWriteLockBase& writeLock)
RT_ZERO(storage);
storage.fCreateDigest = m->fManifest;
storage.fSha256 = m->fSha256;
- vrc = VDInterfaceAdd(&pTarIo->Core, "Appliance::IOTar",
+
+ Utf8Str name = applianceIOName(applianceIOTar);
+
+ vrc = VDInterfaceAdd(&pTarIo->Core, name.c_str(),
VDINTERFACETYPE_IO, tar, sizeof(VDINTERFACEIO),
&storage.pVDImageIfaces);
+
if (RT_FAILURE(vrc))
{
rc = E_FAIL;
break;
}
rc = writeFSImpl(pTask, writeLock, pShaIo, &storage);
- }while(0);
+ } while (0);
RTTarClose(tar);
@@ -1722,7 +2021,7 @@ HRESULT Appliance::writeFSOVA(TaskOVF *pTask, AutoWriteLockBase& writeLock)
RTMemFree(pTarIo);
/* Delete ova file on error */
- if(FAILED(rc))
+ if (FAILED(rc))
RTFileDelete(pTask->locInfo.strPath.c_str());
LogFlowFuncLeave();
@@ -1749,8 +2048,10 @@ HRESULT Appliance::writeFSImpl(TaskOVF *pTask, AutoWriteLockBase& writeLock, PVD
xml::Document doc;
// Now fully build a valid ovf document in memory
buildXML(writeLock, doc, stack, pTask->locInfo.strPath, pTask->enFormat);
+ /* Extract the OVA file name */
+ Utf8Str strOvaFile = pTask->locInfo.strPath;
/* Extract the path */
- Utf8Str strOvfFile = Utf8Str(pTask->locInfo.strPath).stripExt().append(".ovf");
+ Utf8Str strOvfFile = strOvaFile.stripExt().append(".ovf");
// Create a memory buffer containing the XML. */
void *pvBuf = 0;
size_t cbSize;
@@ -1770,12 +2071,16 @@ HRESULT Appliance::writeFSImpl(TaskOVF *pTask, AutoWriteLockBase& writeLock, PVD
}
// We need a proper format description
+ ComObjPtr<MediumFormat> formatTemp;
+
ComObjPtr<MediumFormat> format;
// Scope for the AutoReadLock
{
SystemProperties *pSysProps = mVirtualBox->getSystemProperties();
AutoReadLock propsLock(pSysProps COMMA_LOCKVAL_SRC_POS);
// We are always exporting to VMDK stream optimized for now
+ formatTemp = pSysProps->mediumFormatFromExtension("iso");
+
format = pSysProps->mediumFormat("VMDK");
if (format.isNull())
throw setError(VBOX_E_NOT_SUPPORTED,
@@ -1791,7 +2096,12 @@ HRESULT Appliance::writeFSImpl(TaskOVF *pTask, AutoWriteLockBase& writeLock, PVD
const VirtualSystemDescriptionEntry *pDiskEntry = itS->second;
// source path: where the VBox image is
- const Utf8Str &strSrcFilePath = pDiskEntry->strVboxCurrent;
+ const Utf8Str &strSrcFilePath = pDiskEntry->strVBoxCurrent;
+
+ //skip empty Medium. In common, It's may be empty CD/DVD
+ if (strSrcFilePath.isEmpty() ||
+ pDiskEntry->skipIt == true)
+ continue;
// Do NOT check here whether the file exists. findHardDisk will
// figure that out, and filesystem-based tests are simply wrong
@@ -1801,8 +2111,21 @@ HRESULT Appliance::writeFSImpl(TaskOVF *pTask, AutoWriteLockBase& writeLock, PVD
ComObjPtr<Medium> pSourceDisk;
Log(("Finding source disk \"%s\"\n", strSrcFilePath.c_str()));
- rc = mVirtualBox->findHardDiskByLocation(strSrcFilePath, true, &pSourceDisk);
- if (FAILED(rc)) throw rc;
+
+ if (pDiskEntry->type == VirtualSystemDescriptionType_HardDiskImage)
+ {
+ rc = mVirtualBox->findHardDiskByLocation(strSrcFilePath, true, &pSourceDisk);
+ if (FAILED(rc)) throw rc;
+ }
+ else//may be CD or DVD
+ {
+ rc = mVirtualBox->findDVDOrFloppyImage(DeviceType_DVD,
+ NULL,
+ strSrcFilePath,
+ true,
+ &pSourceDisk);
+ if (FAILED(rc)) throw rc;
+ }
Bstr uuidSource;
rc = pSourceDisk->COMGETTER(Id)(uuidSource.asOutParam());
@@ -1821,22 +2144,118 @@ HRESULT Appliance::writeFSImpl(TaskOVF *pTask, AutoWriteLockBase& writeLock, PVD
writeLock.release();
try
{
- ComObjPtr<Progress> pProgress2;
- pProgress2.createObject();
- rc = pProgress2->init(mVirtualBox, static_cast<IAppliance*>(this), BstrFmt(tr("Creating medium '%s'"), strTargetFilePath.c_str()).raw(), TRUE);
- if (FAILED(rc)) throw rc;
-
// advance to the next operation
pTask->pProgress->SetNextOperation(BstrFmt(tr("Exporting to disk image '%s'"), RTPathFilename(strTargetFilePath.c_str())).raw(),
pDiskEntry->ulSizeMB); // operation's weight, as set up with the IProgress originally
// create a flat copy of the source disk image
- rc = pSourceDisk->exportFile(strTargetFilePath.c_str(), format, MediumVariant_VmdkStreamOptimized, pIfIo, pStorage, pProgress2);
- if (FAILED(rc)) throw rc;
+ if (pDiskEntry->type == VirtualSystemDescriptionType_HardDiskImage)
+ {
+ ComObjPtr<Progress> pProgress2;
+ pProgress2.createObject();
+ rc = pProgress2->init(mVirtualBox, static_cast<IAppliance*>(this), BstrFmt(tr("Creating medium '%s'"), strTargetFilePath.c_str()).raw(), TRUE);
+ if (FAILED(rc)) throw rc;
+
+ rc = pSourceDisk->exportFile(strTargetFilePath.c_str(),
+ format,
+ MediumVariant_VmdkStreamOptimized,
+ pIfIo,
+ pStorage,
+ pProgress2);
+ if (FAILED(rc)) throw rc;
+
+ ComPtr<IProgress> pProgress3(pProgress2);
+ // now wait for the background disk operation to complete; this throws HRESULTs on error
+ waitForAsyncProgress(pTask->pProgress, pProgress3);
+ }
+ else//pDiskEntry->type == VirtualSystemDescriptionType_CDROM
+ {
+ //copy/clone CD/DVD image
+ /* Read the ISO file and add one to OVA/OVF package */
+ {
+ void *pvStorage;
+ RTFILE pFile = NULL;
+ void *pvUser = pStorage;
+
+ vrc = pIfIo->pfnOpen(pvUser, strTargetFilePath.c_str(),
+ RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE,
+ 0,
+ &pvStorage);
+ if (RT_FAILURE(vrc))
+ throw setError(VBOX_E_FILE_ERROR,
+ tr("Could not create or open file '%s' (%Rrc)"),
+ strTargetFilePath.c_str(), vrc);
+
+ vrc = RTFileOpen(&pFile,
+ strSrcFilePath.c_str(),
+ RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE);
+
+ if (RT_FAILURE(vrc) || pFile == NULL)
+ {
+ pIfIo->pfnClose(pvUser, pvStorage);
+ throw setError(VBOX_E_FILE_ERROR,
+ tr("Could not create or open file '%s' (%Rrc)"),
+ strSrcFilePath.c_str(), vrc);
+ }
+
+ void *pvTmpBuf = 0;
+ size_t cbTmpSize = _1M;
+ uint64_t cbAllWritten = 0;
+ uint64_t cbFile = 0;
+ size_t cbSize = 0;
+
+ vrc = RTFileGetSize(pFile, &cbFile);
+
+ do
+ {
+ pvTmpBuf = RTMemAlloc(cbTmpSize);
+ if (!pvTmpBuf)
+ {
+ vrc = VERR_NO_MEMORY;
+ break;
+ }
- ComPtr<IProgress> pProgress3(pProgress2);
- // now wait for the background disk operation to complete; this throws HRESULTs on error
- waitForAsyncProgress(pTask->pProgress, pProgress3);
+ for (;;)
+ {
+ // copy raw data into the buffer pvTmpBuf
+ vrc = RTFileRead(pFile, pvTmpBuf, cbTmpSize, &cbSize);
+
+ if (RT_FAILURE(vrc) || cbSize == 0)
+ break;
+
+ size_t cbToWrite = cbSize;
+ size_t cbWritten = 0;
+
+ vrc = pIfIo->pfnWriteSync(pvUser,
+ pvStorage,
+ cbAllWritten,
+ pvTmpBuf,
+ cbToWrite,&cbWritten);
+
+ if (RT_FAILURE(vrc))
+ break;
+
+ cbAllWritten += cbWritten;
+ }
+ } while (0);
+
+ pIfIo->pfnClose(pvUser, pvStorage);
+ RTFileClose(pFile);
+
+ if (pvTmpBuf)
+ RTMemFree(pvTmpBuf);
+
+ if (RT_FAILURE(vrc))
+ {
+ if (vrc == VERR_EOF)
+ vrc = VINF_SUCCESS;
+ else
+ throw setError(VBOX_E_FILE_ERROR,
+ tr("Error during copy CD/DVD image '%s' (%Rrc)"),
+ strSrcFilePath.c_str(), vrc);
+ }
+ }
+ }
}
catch (HRESULT rc3)
{
diff --git a/src/VBox/Main/src-server/ApplianceImplIO.cpp b/src/VBox/Main/src-server/ApplianceImplIO.cpp
index a31f93a8..1a9ac12a 100644
--- a/src/VBox/Main/src-server/ApplianceImplIO.cpp
+++ b/src/VBox/Main/src-server/ApplianceImplIO.cpp
@@ -1,11 +1,10 @@
/* $Id: ApplianceImplIO.cpp $ */
/** @file
- *
* IO helper for IAppliance COM class implementations.
*/
/*
- * Copyright (C) 2010-2012 Oracle Corporation
+ * Copyright (C) 2010-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -23,19 +22,23 @@
#include "ProgressImpl.h"
#include "ApplianceImpl.h"
#include "ApplianceImplPrivate.h"
+#include "VirtualBoxImpl.h"
+#include <iprt/zip.h>
#include <iprt/tar.h>
#include <iprt/sha.h>
#include <iprt/path.h>
#include <iprt/asm.h>
#include <iprt/stream.h>
#include <iprt/circbuf.h>
+#include <iprt/vfs.h>
+#include <iprt/manifest.h>
+#include <VBox/vd-ifs.h>
#include <VBox/vd.h>
/******************************************************************************
* Structures and Typedefs *
******************************************************************************/
-
typedef struct FILESTORAGEINTERNAL
{
/** File handle. */
@@ -107,13 +110,14 @@ typedef struct SHASTORAGEINTERNAL
#if 0
# define DEBUG_PRINT_FLOW() RTPrintf("%s\n", __FUNCTION__)
#else
-# define DEBUG_PRINT_FLOW() do {} while(0)
+# define DEBUG_PRINT_FLOW() do {} while (0)
#endif
/******************************************************************************
* Internal Functions *
******************************************************************************/
+
/******************************************************************************
* Internal: RTFile interface
******************************************************************************/
@@ -281,7 +285,7 @@ static int tarOpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen
int rc = VINF_SUCCESS;
- if ( fOpen & RTFILE_O_READ
+ if (fOpen & RTFILE_O_READ
&& !(fOpen & RTFILE_O_WRITE))
{
/* Read only is a little bit more complicated than writing, cause we
@@ -297,13 +301,20 @@ static int tarOpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen
*
*/
bool fFound = false;
+
for (;;)
{
char *pszFilename = 0;
rc = RTTarCurrentFile(tar, &pszFilename);
if (RT_SUCCESS(rc))
{
- fFound = !strcmp(pszFilename, RTPathFilename(pszLocation));
+ if (rc == VINF_TAR_DIR_PATH)
+ {
+ break;
+ }
+
+ fFound = !RTStrICmp(pszFilename, pszLocation);
+
RTStrFree(pszFilename);
if (fFound)
break;
@@ -311,7 +322,9 @@ static int tarOpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen
{
rc = RTTarSeekNextFile(tar);
if (RT_FAILURE(rc))
+ {
break;
+ }
}
}
else
@@ -477,7 +490,7 @@ DECLCALLBACK(int) shaCalcWorkerThread(RTTHREAD /* aThread */, void *pvUser)
int rc = VINF_SUCCESS;
bool fLoop = true;
- while(fLoop)
+ while (fLoop)
{
/* What should we do next? */
uint32_t u32Status = ASMAtomicReadU32(&pInt->u32Status);
@@ -755,7 +768,7 @@ static int shaOpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen
rc = shaSignalManifestThread(pInt, STATUS_READ);
}
}
- while(0);
+ while (0);
if (RT_FAILURE(rc))
{
@@ -1014,7 +1027,7 @@ static int shaWriteSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
if ((cbWrite - cbAllWritten) > cbAvail)
{
rc = shaSignalManifestThread(pInt, STATUS_WRITE);
- if(RT_FAILURE(rc))
+ if (RT_FAILURE(rc))
break;
/* If there is _no_ free space available, we have to wait until it is. */
if (cbAvail == 0)
@@ -1084,24 +1097,29 @@ static int shaReadSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
AssertMsgFailed(("Jumping backwards is not possible, sequential access is supported only\n"));
size_t cbAllRead = 0;
+ size_t cbAvail = 0;
for (;;)
{
/* Finished? */
if (cbAllRead == cbRead)
break;
- size_t cbAvail = RTCircBufUsed(pInt->pCircBuf);
+
+ cbAvail = RTCircBufUsed(pInt->pCircBuf);
+
if ( cbAvail == 0
&& pInt->fEOF
&& !RTCircBufIsWriting(pInt->pCircBuf))
{
+ rc = VINF_EOF;
break;
}
+
/* If there isn't enough data make sure the worker thread is fetching
* more. */
if ((cbRead - cbAllRead) > cbAvail)
{
rc = shaSignalManifestThread(pInt, STATUS_READ);
- if(RT_FAILURE(rc))
+ if (RT_FAILURE(rc))
break;
/* If there is _no_ data available, we have to wait until it is. */
if (cbAvail == 0)
@@ -1136,6 +1154,7 @@ static int shaReadSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
/* Signal the thread to read more data in the mean time. */
if ( RT_SUCCESS(rc)
+ && rc != VINF_EOF
&& RTCircBufFree(pInt->pCircBuf) >= (RTCircBufSize(pInt->pCircBuf) / 2))
rc = shaSignalManifestThread(pInt, STATUS_READ);
@@ -1164,10 +1183,6 @@ static int shaFlushSyncCallback(void *pvUser, void *pvStorage)
return vdIfIoFileFlushSync(pIfIo, pInt->pvStorage);
}
-/******************************************************************************
- * Public Functions *
- ******************************************************************************/
-
PVDINTERFACEIO ShaCreateInterface()
{
PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
@@ -1274,7 +1289,7 @@ int ShaReadBuf(const char *pcszFilename, void **ppvBuf, size_t *pcbSize, PVDINTE
memcpy(&((char*)pvBuf)[cbAllRead], pvTmpBuf, cbRead);
cbAllRead += cbRead;
}
- }while(0);
+ } while (0);
pIfIo->pfnClose(pvUser, pvStorage);
@@ -1325,8 +1340,152 @@ int ShaWriteBuf(const char *pcszFilename, void *pvBuf, size_t cbSize, PVDINTERFA
cbAllWritten += cbWritten;
}
+ rc = pIfIo->pfnClose(pvUser, pvStorage);
+
+ return rc;
+}
+
+int decompressImageAndSave(const char *pcszFullFilenameIn, const char *pcszFullFilenameOut, PVDINTERFACEIO pIfIo, void *pvUser)
+{
+ /* Validate input. */
+ AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
+
+ PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
+ /*
+ * Open the source file.
+ */
+ void *pvStorage;
+ int rc = pIfIo->pfnOpen(pvUser, pcszFullFilenameIn,
+ RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, 0,
+ &pvStorage);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* Turn the source file handle/whatever into a VFS stream. */
+ RTVFSIOSTREAM hVfsIosCompressedSrc;
+
+ rc = VDIfCreateVfsStream(pIfIo, pvStorage, RTFILE_O_READ, &hVfsIosCompressedSrc);
+ if (RT_SUCCESS(rc))
+ {
+ /* Pass the source thru gunzip. */
+ RTVFSIOSTREAM hVfsIosSrc;
+ rc = RTZipGzipDecompressIoStream(hVfsIosCompressedSrc, 0, &hVfsIosSrc);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Create the output file, including necessary paths.
+ * Any existing file will be overwritten.
+ */
+ rc = VirtualBox::ensureFilePathExists(Utf8Str(pcszFullFilenameOut), true /*fCreate*/);
+ if (RT_SUCCESS(rc))
+ {
+ RTVFSIOSTREAM hVfsIosDst;
+ rc = RTVfsIoStrmOpenNormal(pcszFullFilenameOut,
+ RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL,
+ &hVfsIosDst);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Pump the bytes thru. If we fail, delete the output file.
+ */
+ RTMANIFEST hFileManifest = NIL_RTMANIFEST;
+ rc = RTManifestCreate(0 /*fFlags*/, &hFileManifest);
+ if (RT_SUCCESS(rc))
+ {
+ RTVFSIOSTREAM hVfsIosMfst;
+
+ uint32_t digestType = (pShaStorage->fSha256 == true) ? RTMANIFEST_ATTR_SHA256: RTMANIFEST_ATTR_SHA1;
+
+ rc = RTManifestEntryAddPassthruIoStream(hFileManifest,
+ hVfsIosSrc,
+ "ovf import",
+ digestType,
+ true /*read*/, &hVfsIosMfst);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTVfsUtilPumpIoStreams(hVfsIosMfst, hVfsIosDst, 0);
+ }
+
+ RTVfsIoStrmRelease(hVfsIosMfst);
+ }
+
+ RTVfsIoStrmRelease(hVfsIosDst);
+ }
+ }
+
+ RTVfsIoStrmRelease(hVfsIosSrc);
+ }
+ }
pIfIo->pfnClose(pvUser, pvStorage);
return rc;
}
+int copyFileAndCalcShaDigest(const char *pcszSourceFilename, const char *pcszTargetFilename, PVDINTERFACEIO pIfIo, void *pvUser)
+{
+ /* Validate input. */
+ AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
+
+ PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
+ void *pvStorage;
+
+ int rc = pIfIo->pfnOpen(pvUser, pcszSourceFilename,
+ RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, 0,
+ &pvStorage);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* Turn the source file handle/whatever into a VFS stream. */
+ RTVFSIOSTREAM hVfsIosSrc;
+
+ rc = VDIfCreateVfsStream(pIfIo, pvStorage, RTFILE_O_READ, &hVfsIosSrc);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Create the output file, including necessary paths.
+ * Any existing file will be overwritten.
+ */
+ rc = VirtualBox::ensureFilePathExists(Utf8Str(pcszTargetFilename), true /*fCreate*/);
+ if (RT_SUCCESS(rc))
+ {
+ RTVFSIOSTREAM hVfsIosDst;
+ rc = RTVfsIoStrmOpenNormal(pcszTargetFilename,
+ RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL,
+ &hVfsIosDst);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Pump the bytes thru. If we fail, delete the output file.
+ */
+ RTMANIFEST hFileManifest = NIL_RTMANIFEST;
+ rc = RTManifestCreate(0 /*fFlags*/, &hFileManifest);
+ if (RT_SUCCESS(rc))
+ {
+ RTVFSIOSTREAM hVfsIosMfst;
+
+ uint32_t digestType = (pShaStorage->fSha256 == true) ? RTMANIFEST_ATTR_SHA256: RTMANIFEST_ATTR_SHA1;
+
+ rc = RTManifestEntryAddPassthruIoStream(hFileManifest,
+ hVfsIosSrc,
+ "ovf import",
+ digestType,
+ true /*read*/, &hVfsIosMfst);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTVfsUtilPumpIoStreams(hVfsIosMfst, hVfsIosDst, 0);
+ }
+
+ RTVfsIoStrmRelease(hVfsIosMfst);
+ }
+
+ RTVfsIoStrmRelease(hVfsIosDst);
+ }
+ }
+
+ RTVfsIoStrmRelease(hVfsIosSrc);
+
+ }
+
+ pIfIo->pfnClose(pvUser, pvStorage);
+ return rc;
+}
diff --git a/src/VBox/Main/src-server/ApplianceImplImport.cpp b/src/VBox/Main/src-server/ApplianceImplImport.cpp
index 447d717f..1eada736 100644
--- a/src/VBox/Main/src-server/ApplianceImplImport.cpp
+++ b/src/VBox/Main/src-server/ApplianceImplImport.cpp
@@ -1,11 +1,10 @@
/* $Id: ApplianceImplImport.cpp $ */
/** @file
- *
* IAppliance and IVirtualSystem COM class implementations.
*/
/*
- * Copyright (C) 2008-2012 Oracle Corporation
+ * Copyright (C) 2008-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -47,6 +46,8 @@
#include <VBox/version.h>
#include <VBox/settings.h>
+#include <set>
+
using namespace std;
////////////////////////////////////////////////////////////////////////////////
@@ -116,7 +117,8 @@ STDMETHODIMP Appliance::Read(IN_BSTR path, IProgress **aProgress)
STDMETHODIMP Appliance::Interpret()
{
// @todo:
- // - don't use COM methods but the methods directly (faster, but needs appropriate locking of that objects itself (s. HardDisk))
+ // - don't use COM methods but the methods directly (faster, but needs appropriate
+ // locking of that objects itself (s. HardDisk))
// - Appropriate handle errors like not supported file formats
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
@@ -160,21 +162,21 @@ STDMETHODIMP Appliance::Interpret()
// if the virtual system in OVF had a <vbox:Machine> element, have the
// VirtualBox settings code parse that XML now
- if (vsysThis.pelmVboxMachine)
- pNewDesc->importVboxMachineXML(*vsysThis.pelmVboxMachine);
+ if (vsysThis.pelmVBoxMachine)
+ pNewDesc->importVBoxMachineXML(*vsysThis.pelmVBoxMachine);
// Guest OS type
// This is taken from one of three places, in this order:
Utf8Str strOsTypeVBox;
Utf8StrFmt strCIMOSType("%RU32", (uint32_t)vsysThis.cimos);
// 1) If there is a <vbox:Machine>, then use the type from there.
- if ( vsysThis.pelmVboxMachine
+ if ( vsysThis.pelmVBoxMachine
&& pNewDesc->m->pConfig->machineUserData.strOsType.isNotEmpty()
)
strOsTypeVBox = pNewDesc->m->pConfig->machineUserData.strOsType;
// 2) Otherwise, if there is OperatingSystemSection/vbox:OSType, use that one.
- else if (vsysThis.strTypeVbox.isNotEmpty()) // OVFReader has found vbox:OSType
- strOsTypeVBox = vsysThis.strTypeVbox;
+ else if (vsysThis.strTypeVBox.isNotEmpty()) // OVFReader has found vbox:OSType
+ strOsTypeVBox = vsysThis.strTypeVBox;
// 3) Otherwise, make a best guess what the vbox type is from the OVF (CIM) OS type.
else
convertCIMOSType2VBoxOSType(strOsTypeVBox, vsysThis.cimos, vsysThis.strCimosDesc);
@@ -186,7 +188,7 @@ STDMETHODIMP Appliance::Interpret()
/* VM name */
Utf8Str nameVBox;
/* If there is a <vbox:Machine>, we always prefer the setting from there. */
- if ( vsysThis.pelmVboxMachine
+ if ( vsysThis.pelmVBoxMachine
&& pNewDesc->m->pConfig->machineUserData.strName.isNotEmpty())
nameVBox = pNewDesc->m->pConfig->machineUserData.strName;
else
@@ -269,7 +271,7 @@ STDMETHODIMP Appliance::Interpret()
/* CPU count */
ULONG cpuCountVBox;
/* If there is a <vbox:Machine>, we always prefer the setting from there. */
- if ( vsysThis.pelmVboxMachine
+ if ( vsysThis.pelmVBoxMachine
&& pNewDesc->m->pConfig->hardwareMachine.cCPUs)
cpuCountVBox = pNewDesc->m->pConfig->hardwareMachine.cCPUs;
else
@@ -277,7 +279,8 @@ STDMETHODIMP Appliance::Interpret()
/* Check for the constraints */
if (cpuCountVBox > SchemaDefs::MaxCPUCount)
{
- addWarning(tr("The virtual system \"%s\" claims support for %u CPU's, but VirtualBox has support for max %u CPU's only."),
+ addWarning(tr("The virtual system \"%s\" claims support for %u CPU's, but VirtualBox has support for "
+ "max %u CPU's only."),
vsysThis.strName.c_str(), cpuCountVBox, SchemaDefs::MaxCPUCount);
cpuCountVBox = SchemaDefs::MaxCPUCount;
}
@@ -291,7 +294,7 @@ STDMETHODIMP Appliance::Interpret()
/* RAM */
uint64_t ullMemSizeVBox;
/* If there is a <vbox:Machine>, we always prefer the setting from there. */
- if ( vsysThis.pelmVboxMachine
+ if ( vsysThis.pelmVBoxMachine
&& pNewDesc->m->pConfig->hardwareMachine.ulMemorySizeMB)
ullMemSizeVBox = pNewDesc->m->pConfig->hardwareMachine.ulMemorySizeMB;
else
@@ -303,7 +306,8 @@ STDMETHODIMP Appliance::Interpret()
)
)
{
- addWarning(tr("The virtual system \"%s\" claims support for %llu MB RAM size, but VirtualBox has support for min %u & max %u MB RAM size only."),
+ addWarning(tr("The virtual system \"%s\" claims support for %llu MB RAM size, but VirtualBox has "
+ "support for min %u & max %u MB RAM size only."),
vsysThis.strName.c_str(), ullMemSizeVBox, MM_RAM_MIN_IN_MB, MM_RAM_MAX_IN_MB);
ullMemSizeVBox = RT_MIN(RT_MAX(ullMemSizeVBox, MM_RAM_MIN_IN_MB), MM_RAM_MAX_IN_MB);
}
@@ -325,9 +329,12 @@ STDMETHODIMP Appliance::Interpret()
Utf8Str strSoundCard;
Utf8Str strSoundCardOrig;
/* If there is a <vbox:Machine>, we always prefer the setting from there. */
- if ( vsysThis.pelmVboxMachine
+ if ( vsysThis.pelmVBoxMachine
&& pNewDesc->m->pConfig->hardwareMachine.audioAdapter.fEnabled)
- strSoundCard = Utf8StrFmt("%RU32", (uint32_t)pNewDesc->m->pConfig->hardwareMachine.audioAdapter.controllerType);
+ {
+ strSoundCard = Utf8StrFmt("%RU32",
+ (uint32_t)pNewDesc->m->pConfig->hardwareMachine.audioAdapter.controllerType);
+ }
else if (vsysThis.strSoundCardType.isNotEmpty())
{
/* Set the AC97 always for the simple OVF case.
@@ -344,22 +351,23 @@ STDMETHODIMP Appliance::Interpret()
#ifdef VBOX_WITH_USB
/* USB Controller */
/* If there is a <vbox:Machine>, we always prefer the setting from there. */
- if ( ( vsysThis.pelmVboxMachine
- && pNewDesc->m->pConfig->hardwareMachine.usbController.fEnabled)
+ if ( ( vsysThis.pelmVBoxMachine
+ && pNewDesc->m->pConfig->hardwareMachine.usbSettings.llUSBControllers.size() > 0)
|| vsysThis.fHasUsbController)
pNewDesc->addEntry(VirtualSystemDescriptionType_USBController, "", "", "");
#endif /* VBOX_WITH_USB */
/* Network Controller */
/* If there is a <vbox:Machine>, we always prefer the setting from there. */
- if (vsysThis.pelmVboxMachine)
+ if (vsysThis.pelmVBoxMachine)
{
uint32_t maxNetworkAdapters = Global::getMaxNetworkAdapters(pNewDesc->m->pConfig->hardwareMachine.chipsetType);
const settings::NetworkAdaptersList &llNetworkAdapters = pNewDesc->m->pConfig->hardwareMachine.llNetworkAdapters;
/* Check for the constrains */
if (llNetworkAdapters.size() > maxNetworkAdapters)
- addWarning(tr("The virtual system \"%s\" claims support for %zu network adapters, but VirtualBox has support for max %u network adapter only."),
+ addWarning(tr("The virtual system \"%s\" claims support for %zu network adapters, but VirtualBox "
+ "has support for max %u network adapter only."),
vsysThis.strName.c_str(), llNetworkAdapters.size(), maxNetworkAdapters);
/* Iterate through all network adapters. */
settings::NetworkAdaptersList::const_iterator it1;
@@ -387,7 +395,8 @@ STDMETHODIMP Appliance::Interpret()
/* Check for the constrains */
if (cEthernetAdapters > maxNetworkAdapters)
- addWarning(tr("The virtual system \"%s\" claims support for %zu network adapters, but VirtualBox has support for max %u network adapter only."),
+ addWarning(tr("The virtual system \"%s\" claims support for %zu network adapters, but VirtualBox "
+ "has support for max %u network adapter only."),
vsysThis.strName.c_str(), cEthernetAdapters, maxNetworkAdapters);
/* Get the default network adapter type for the selected guest OS */
@@ -462,7 +471,7 @@ STDMETHODIMP Appliance::Interpret()
/* If there is a <vbox:Machine>, we always prefer the setting from there. */
bool fFloppy = false;
bool fDVD = false;
- if (vsysThis.pelmVboxMachine)
+ if (vsysThis.pelmVBoxMachine)
{
settings::StorageControllersList &llControllers = pNewDesc->m->pConfig->storageMachine.llStorageControllers;
settings::StorageControllersList::iterator it3;
@@ -526,12 +535,13 @@ STDMETHODIMP Appliance::Interpret()
pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerIDE,
strControllerID, // strRef
hdc.strControllerType, // aOvfValue
- strType); // aVboxValue
+ strType); // aVBoxValue
}
else
/* Warn only once */
if (cIDEused == 2)
- addWarning(tr("The virtual \"%s\" system requests support for more than two IDE controller channels, but VirtualBox supports only two."),
+ addWarning(tr("The virtual \"%s\" system requests support for more than two "
+ "IDE controller channels, but VirtualBox supports only two."),
vsysThis.strName.c_str());
++cIDEused;
@@ -552,7 +562,8 @@ STDMETHODIMP Appliance::Interpret()
{
/* Warn only once */
if (cSATAused == 1)
- addWarning(tr("The virtual system \"%s\" requests support for more than one SATA controller, but VirtualBox has support for only one"),
+ addWarning(tr("The virtual system \"%s\" requests support for more than one "
+ "SATA controller, but VirtualBox has support for only one"),
vsysThis.strName.c_str());
}
@@ -579,7 +590,9 @@ STDMETHODIMP Appliance::Interpret()
hdcController);
}
else
- addWarning(tr("The virtual system \"%s\" requests support for an additional SCSI controller of type \"%s\" with ID %s, but VirtualBox presently supports only one SCSI controller."),
+ addWarning(tr("The virtual system \"%s\" requests support for an additional "
+ "SCSI controller of type \"%s\" with ID %s, but VirtualBox presently "
+ "supports only one SCSI controller."),
vsysThis.strName.c_str(),
hdc.strControllerType.c_str(),
strControllerID.c_str());
@@ -599,22 +612,96 @@ STDMETHODIMP Appliance::Interpret()
{
const ovf::VirtualDisk &hd = itVD->second;
/* Get the associated disk image */
- const ovf::DiskImage &di = m->pReader->m_mapDisks[hd.strDiskId];
+ ovf::DiskImage di;
+ std::map<RTCString, ovf::DiskImage>::iterator foundDisk;
+
+ foundDisk = m->pReader->m_mapDisks.find(hd.strDiskId);
+ if (foundDisk == m->pReader->m_mapDisks.end())
+ continue;
+ else
+ {
+ di = foundDisk->second;
+ }
+
+ /*
+ * Figure out from URI which format the image of disk has.
+ * URI must have inside section <Disk> .
+ * But there aren't strong requirements about correspondence one URI for one disk virtual format.
+ * So possibly, we aren't able to recognize some URIs.
+ */
+ Utf8Str vdf = typeOfVirtualDiskFormatFromURI(di.strFormat);
+
+ /*
+ * fallback, if we can't determine virtual disk format using URI from the attribute ovf:format
+ * in the corresponding section <Disk> in the OVF file.
+ */
+ if (vdf.isEmpty())
+ {
+ /* Figure out from extension which format the image of disk has. */
+ {
+ char *pszExt = RTPathExt(di.strHref.c_str());
+ /* Get the system properties. */
+ SystemProperties *pSysProps = mVirtualBox->getSystemProperties();
+ ComObjPtr<MediumFormat> trgFormat = pSysProps->mediumFormatFromExtension(&pszExt[1]);
+ if (trgFormat.isNull())
+ {
+ throw setError(E_FAIL,
+ tr("Internal inconsistency looking up medium format for the disk image '%s'"),
+ di.strHref.c_str());
+ }
+
+ Bstr bstrFormatName;
+ rc = trgFormat->COMGETTER(Name)(bstrFormatName.asOutParam());
+ if (FAILED(rc))
+ throw rc;
+
+ vdf = Utf8Str(bstrFormatName);
+ }
+ }
// @todo:
// - figure out all possible vmdk formats we also support
// - figure out if there is a url specifier for vhd already
// - we need a url specifier for the vdi format
- if ( di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#sparse", Utf8Str::CaseInsensitive)
- || di.strFormat.compare("http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized", Utf8Str::CaseInsensitive)
- || di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#compressed", Utf8Str::CaseInsensitive)
- || di.strFormat.compare("http://www.vmware.com/interfaces/specifications/vmdk.html#compressed", Utf8Str::CaseInsensitive)
- )
+
+ if (vdf.compare("VMDK", Utf8Str::CaseInsensitive) == 0)
{
/* If the href is empty use the VM name as filename */
Utf8Str strFilename = di.strHref;
if (!strFilename.length())
- strFilename = Utf8StrFmt("%s.vmdk", nameVBox.c_str());
+ strFilename = Utf8StrFmt("%s.vmdk", hd.strDiskId.c_str());
+
+ Utf8Str strTargetPath = Utf8Str(strMachineFolder);
+ strTargetPath.append(RTPATH_DELIMITER).append(di.strHref);
+ searchUniqueDiskImageFilePath(strTargetPath);
+
+ /* find the description for the hard disk controller
+ * that has the same ID as hd.idController */
+ const VirtualSystemDescriptionEntry *pController;
+ if (!(pController = pNewDesc->findControllerFromID(hd.idController)))
+ throw setError(E_FAIL,
+ tr("Cannot find hard disk controller with OVF instance ID %RI32 "
+ "to which disk \"%s\" should be attached"),
+ hd.idController,
+ di.strHref.c_str());
+
+ /* controller to attach to, and the bus within that controller */
+ Utf8StrFmt strExtraConfig("controller=%RI16;channel=%RI16",
+ pController->ulIndex,
+ hd.ulAddressOnParent);
+ pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskImage,
+ hd.strDiskId,
+ di.strHref,
+ strTargetPath,
+ di.ulSuggestedSizeMB,
+ strExtraConfig);
+ }
+ else if (vdf.compare("RAW", Utf8Str::CaseInsensitive) == 0)
+ {
+ /* If the href is empty use the VM name as filename */
+ Utf8Str strFilename = di.strHref;
+ if (!strFilename.length())
+ strFilename = Utf8StrFmt("%s.iso", hd.strDiskId.c_str());
Utf8Str strTargetPath = Utf8Str(strMachineFolder)
.append(RTPATH_DELIMITER)
@@ -626,7 +713,8 @@ STDMETHODIMP Appliance::Interpret()
const VirtualSystemDescriptionEntry *pController;
if (!(pController = pNewDesc->findControllerFromID(hd.idController)))
throw setError(E_FAIL,
- tr("Cannot find hard disk controller with OVF instance ID %RI32 to which disk \"%s\" should be attached"),
+ tr("Cannot find disk controller with OVF instance ID %RI32 "
+ "to which disk \"%s\" should be attached"),
hd.idController,
di.strHref.c_str());
@@ -643,7 +731,9 @@ STDMETHODIMP Appliance::Interpret()
}
else
throw setError(VBOX_E_FILE_ERROR,
- tr("Unsupported format for virtual disk image in OVF: \"%s\"", di.strFormat.c_str()));
+ tr("Unsupported format for virtual disk image %s in OVF: \"%s\""),
+ di.strHref.c_str(),
+ di.strFormat.c_str());
}
}
@@ -678,12 +768,12 @@ STDMETHODIMP Appliance::ImportMachines(ComSafeArrayIn(ImportOptions_T, options),
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
- if (options != NULL)
- m->optList = com::SafeArray<ImportOptions_T>(ComSafeArrayInArg(options)).toList();
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
- AssertReturn(!(m->optList.contains(ImportOptions_KeepAllMACs) && m->optList.contains(ImportOptions_KeepNATMACs)), E_INVALIDARG);
+ if (options != NULL)
+ m->optListImport = com::SafeArray<ImportOptions_T>(ComSafeArrayInArg(options)).toList();
- AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+ AssertReturn(!(m->optListImport.contains(ImportOptions_KeepAllMACs) && m->optListImport.contains(ImportOptions_KeepNATMACs)), E_INVALIDARG);
// do not allow entering this method if the appliance is busy reading or writing
if (!isApplianceIdle())
@@ -717,6 +807,35 @@ STDMETHODIMP Appliance::ImportMachines(ComSafeArrayIn(ImportOptions_T, options),
//
////////////////////////////////////////////////////////////////////////////////
+HRESULT Appliance::preCheckImageAvailability(PSHASTORAGE pSHAStorage,
+ RTCString &availableImage)
+{
+ HRESULT rc = S_OK;
+ RTTAR tar = (RTTAR)pSHAStorage->pVDImageIfaces->pvUser;
+ char *pszFilename = 0;
+
+ int vrc = RTTarCurrentFile(tar, &pszFilename);
+
+ if (RT_FAILURE(vrc))
+ {
+ throw setError(VBOX_E_FILE_ERROR,
+ tr("Could not open the current file in the OVA package (%Rrc)"), vrc);
+ }
+ else
+ {
+ if (vrc == VINF_TAR_DIR_PATH)
+ {
+ throw setError(VBOX_E_FILE_ERROR,
+ tr("Empty directory folder (%s) isn't allowed in the OVA package (%Rrc)"),
+ pszFilename,
+ vrc);
+ }
+ }
+
+ availableImage = pszFilename;
+
+ return rc;
+}
/*******************************************************************************
* Read stuff
@@ -818,36 +937,125 @@ HRESULT Appliance::readFSOVF(TaskOVF *pTask)
LogFlowFuncEnter();
HRESULT rc = S_OK;
+ int vrc = VINF_SUCCESS;
PVDINTERFACEIO pShaIo = 0;
PVDINTERFACEIO pFileIo = 0;
do
{
- pShaIo = ShaCreateInterface();
- if (!pShaIo)
- {
- rc = E_OUTOFMEMORY;
- break;
- }
- pFileIo = FileCreateInterface();
- if (!pFileIo)
+ try
{
- rc = E_OUTOFMEMORY;
- break;
+ /* Create the necessary file access interfaces. */
+ pFileIo = FileCreateInterface();
+ if (!pFileIo)
+ {
+ rc = E_OUTOFMEMORY;
+ break;
+ }
+
+ Utf8Str strMfFile = Utf8Str(pTask->locInfo.strPath).stripExt().append(".mf");
+
+ SHASTORAGE storage;
+ RT_ZERO(storage);
+
+ if (RTFileExists(strMfFile.c_str()))
+ {
+ pShaIo = ShaCreateInterface();
+ if (!pShaIo)
+ {
+ rc = E_OUTOFMEMORY;
+ break;
+ }
+
+ //read the manifest file and find a type of used digest
+ RTFILE pFile = NULL;
+ vrc = RTFileOpen(&pFile, strMfFile.c_str(), RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE);
+ if (RT_SUCCESS(vrc) && pFile != NULL)
+ {
+ uint64_t cbFile = 0;
+ uint64_t maxFileSize = _1M;
+ size_t cbRead = 0;
+ void *pBuf; /** @todo r=bird: You leak this buffer! throwing stuff is evil. */
+
+ vrc = RTFileGetSize(pFile, &cbFile);
+ if (cbFile > maxFileSize)
+ throw setError(VBOX_E_FILE_ERROR,
+ tr("Size of the manifest file '%s' is bigger than 1Mb. Check it, please."),
+ RTPathFilename(strMfFile.c_str()));
+
+ if (RT_SUCCESS(vrc))
+ pBuf = RTMemAllocZ(cbFile);
+ else
+ throw setError(VBOX_E_FILE_ERROR,
+ tr("Could not get size of the manifest file '%s' "),
+ RTPathFilename(strMfFile.c_str()));
+
+ vrc = RTFileRead(pFile, pBuf, cbFile, &cbRead);
+
+ if (RT_FAILURE(vrc))
+ {
+ if (pBuf)
+ RTMemFree(pBuf);
+ throw setError(VBOX_E_FILE_ERROR,
+ tr("Could not read the manifest file '%s' (%Rrc)"),
+ RTPathFilename(strMfFile.c_str()), vrc);
+ }
+
+ RTFileClose(pFile);
+
+ RTDIGESTTYPE digestType;
+ vrc = RTManifestVerifyDigestType(pBuf, cbRead, &digestType);
+
+ if (pBuf)
+ RTMemFree(pBuf);
+
+ if (RT_FAILURE(vrc))
+ {
+ throw setError(VBOX_E_FILE_ERROR,
+ tr("Could not verify supported digest types in the manifest file '%s' (%Rrc)"),
+ RTPathFilename(strMfFile.c_str()), vrc);
+ }
+
+ storage.fCreateDigest = true;
+
+ if (digestType == RTDIGESTTYPE_SHA256)
+ {
+ storage.fSha256 = true;
+ }
+
+ Utf8Str name = applianceIOName(applianceIOFile);
+
+ vrc = VDInterfaceAdd(&pFileIo->Core, name.c_str(),
+ VDINTERFACETYPE_IO, 0, sizeof(VDINTERFACEIO),
+ &storage.pVDImageIfaces);
+ if (RT_FAILURE(vrc))
+ throw setError(VBOX_E_IPRT_ERROR, "Creation of the VD interface failed (%Rrc)", vrc);
+
+ rc = readFSImpl(pTask, pTask->locInfo.strPath, pShaIo, &storage);
+ if (FAILED(rc))
+ break;
+ }
+ else
+ {
+ throw setError(VBOX_E_FILE_ERROR,
+ tr("Could not open the manifest file '%s' (%Rrc)"),
+ RTPathFilename(strMfFile.c_str()), vrc);
+ }
+ }
+ else
+ {
+ storage.fCreateDigest = false;
+ rc = readFSImpl(pTask, pTask->locInfo.strPath, pFileIo, &storage);
+ if (FAILED(rc))
+ break;
+ }
}
- SHASTORAGE storage;
- RT_ZERO(storage);
- int vrc = VDInterfaceAdd(&pFileIo->Core, "Appliance::IOFile",
- VDINTERFACETYPE_IO, 0, sizeof(VDINTERFACEIO),
- &storage.pVDImageIfaces);
- if (RT_FAILURE(vrc))
+ catch (HRESULT rc2)
{
- rc = setError(VBOX_E_IPRT_ERROR, "Creation of the VD interface failed (%Rrc)", vrc);
- break;
+ rc = rc2;
}
- rc = readFSImpl(pTask, pTask->locInfo.strPath, pShaIo, &storage);
- }while(0);
+ }while (0);
/* Cleanup */
if (pShaIo)
@@ -866,51 +1074,79 @@ HRESULT Appliance::readFSOVA(TaskOVF *pTask)
LogFlowFuncEnter();
RTTAR tar;
- int vrc = RTTarOpen(&tar, pTask->locInfo.strPath.c_str(), RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, true);
- if (RT_FAILURE(vrc))
- return setError(VBOX_E_FILE_ERROR,
- tr("Could not open OVA file '%s' (%Rrc)"),
- pTask->locInfo.strPath.c_str(), vrc);
-
HRESULT rc = S_OK;
-
+ int vrc = 0;
PVDINTERFACEIO pShaIo = 0;
PVDINTERFACEIO pTarIo = 0;
char *pszFilename = 0;
- do
+ SHASTORAGE storage;
+
+ RT_ZERO(storage);
+
+ vrc = RTTarOpen(&tar, pTask->locInfo.strPath.c_str(), RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, true);
+ if (RT_FAILURE(vrc))
+ rc = setError(VBOX_E_FILE_ERROR,
+ tr("Could not open the OVA file '%s' (%Rrc)"),
+ pTask->locInfo.strPath.c_str(), vrc);
+ else
{
- vrc = RTTarCurrentFile(tar, &pszFilename);
- if (RT_FAILURE(vrc))
- {
- rc = VBOX_E_FILE_ERROR;
- break;
- }
- pShaIo = ShaCreateInterface();
- if (!pShaIo)
- {
- rc = E_OUTOFMEMORY;
- break;
- }
- pTarIo = TarCreateInterface();
- if (!pTarIo)
- {
- rc = E_OUTOFMEMORY;
- break;
- }
- SHASTORAGE storage;
- RT_ZERO(storage);
- vrc = VDInterfaceAdd(&pTarIo->Core, "Appliance::IOTar",
- VDINTERFACETYPE_IO, tar, sizeof(VDINTERFACEIO),
- &storage.pVDImageIfaces);
- if (RT_FAILURE(vrc))
+ do
{
- rc = setError(VBOX_E_IPRT_ERROR, "Creation of the VD interface failed (%Rrc)", vrc);
- break;
- }
- rc = readFSImpl(pTask, pszFilename, pShaIo, &storage);
- }while(0);
+ vrc = RTTarCurrentFile(tar, &pszFilename);
+ if (RT_FAILURE(vrc))
+ {
+ rc = VBOX_E_FILE_ERROR;
+ break;
+ }
+
+ Utf8Str extension(RTPathExt(pszFilename));
+
+ if (!extension.endsWith(".ovf",Utf8Str::CaseInsensitive))
+ {
+ vrc = VERR_FILE_NOT_FOUND;
+ rc = setError(VBOX_E_FILE_ERROR,
+ tr("First file in the OVA package must have the extension 'ovf'. "
+ "But the file '%s' has the different extension (%Rrc)"),
+ pszFilename,
+ vrc);
+ break;
+ }
+
+ pTarIo = TarCreateInterface();
+ if (!pTarIo)
+ {
+ rc = E_OUTOFMEMORY;
+ break;
+ }
+
+ pShaIo = ShaCreateInterface();
+ if (!pShaIo)
+ {
+ rc = E_OUTOFMEMORY;
+ break ;
+ }
+
+ Utf8Str name = applianceIOName(applianceIOTar);
+
+ vrc = VDInterfaceAdd(&pTarIo->Core, name.c_str(),
+ VDINTERFACETYPE_IO, tar, sizeof(VDINTERFACEIO),
+ &storage.pVDImageIfaces);
+ if (RT_FAILURE(vrc))
+ {
+ rc = setError(VBOX_E_IPRT_ERROR, "Creation of the VD interface failed (%Rrc)", vrc);
+ break;
+ }
+
+ rc = readFSImpl(pTask, pszFilename, pShaIo, &storage);
+ if (FAILED(rc))
+ break;
+
+ } while (0);
+
+ RTTarClose(tar);
+ }
+
- RTTarClose(tar);
/* Cleanup */
if (pszFilename)
@@ -940,15 +1176,49 @@ HRESULT Appliance::readFSImpl(TaskOVF *pTask, const RTCString &strFilename, PVDI
/* Read the OVF into a memory buffer */
size_t cbSize = 0;
int vrc = ShaReadBuf(strFilename.c_str(), &pvTmpBuf, &cbSize, pIfIo, pStorage);
- if ( RT_FAILURE(vrc)
+ if (RT_FAILURE(vrc)
|| !pvTmpBuf)
throw setError(VBOX_E_FILE_ERROR,
tr("Could not read OVF file '%s' (%Rrc)"),
RTPathFilename(strFilename.c_str()), vrc);
- /* Copy the SHA1/SHA256 sum of the OVF file for later validation */
- m->strOVFSHADigest = pStorage->strDigest;
+
/* Read & parse the XML structure of the OVF file */
m->pReader = new ovf::OVFReader(pvTmpBuf, cbSize, pTask->locInfo.strPath);
+
+ if (m->pReader->m_envelopeData.getOVFVersion() == ovf::OVFVersion_2_0)
+ {
+ m->fSha256 = true;
+
+ uint8_t digest[RTSHA256_HASH_SIZE];
+ size_t cbDigest = RTSHA256_DIGEST_LEN;
+ char *pszDigest;
+
+ RTSha256(pvTmpBuf, cbSize, &digest[0]);
+
+ vrc = RTStrAllocEx(&pszDigest, cbDigest + 1);
+ if (RT_SUCCESS(vrc))
+ vrc = RTSha256ToString(digest, pszDigest, cbDigest + 1);
+ else
+ throw setError(VBOX_E_FILE_ERROR,
+ tr("Could not allocate string for SHA256 digest (%Rrc)"), vrc);
+
+ if (RT_SUCCESS(vrc))
+ /* Copy the SHA256 sum of the OVF file for later validation */
+ m->strOVFSHADigest = pszDigest;
+ else
+ throw setError(VBOX_E_FILE_ERROR,
+ tr("Converting SHA256 digest to a string was failed (%Rrc)"), vrc);
+
+ RTStrFree(pszDigest);
+
+ }
+ else
+ {
+ m->fSha256 = false;
+ /* Copy the SHA1 sum of the OVF file for later validation */
+ m->strOVFSHADigest = pStorage->strDigest;
+ }
+
}
catch (RTCError &x) // includes all XML exceptions
{
@@ -1017,7 +1287,11 @@ HRESULT Appliance::readS3(TaskOVF *pTask)
strTmpOvf = Utf8StrFmt("%s/%s", pszTmpDir, RTPathFilename(tmpPath.c_str()));
/* Next we have to download the OVF */
- vrc = RTS3Create(&hS3, pTask->locInfo.strUsername.c_str(), pTask->locInfo.strPassword.c_str(), pTask->locInfo.strHostname.c_str(), "virtualbox-agent/"VBOX_VERSION_STRING);
+ vrc = RTS3Create(&hS3,
+ pTask->locInfo.strUsername.c_str(),
+ pTask->locInfo.strPassword.c_str(),
+ pTask->locInfo.strHostname.c_str(),
+ "virtualbox-agent/"VBOX_VERSION_STRING);
if (RT_FAILURE(vrc))
throw setError(VBOX_E_IPRT_ERROR,
tr("Cannot create S3 service handler"));
@@ -1032,7 +1306,8 @@ HRESULT Appliance::readS3(TaskOVF *pTask)
throw S_OK; /* todo: !!!!!!!!!!!!! */
else if (vrc == VERR_S3_ACCESS_DENIED)
throw setError(E_ACCESSDENIED,
- tr("Cannot download file '%s' from S3 storage server (Access denied). Make sure that your credentials are right."
+ tr("Cannot download file '%s' from S3 storage server (Access denied). Make sure that "
+ "your credentials are right. "
"Also check that your host clock is properly synced"),
pszFilename);
else if (vrc == VERR_S3_NOT_FOUND)
@@ -1148,9 +1423,12 @@ HRESULT Appliance::importImpl(const LocationInfo &locInfo,
}
/**
- * Actual worker code for importing OVF data into VirtualBox. This is called from Appliance::taskThreadImportOrExport()
- * and therefore runs on the OVF import worker thread. This creates one or more new machines according to the
- * VirtualSystemScription instances created by Appliance::Interpret().
+ * Actual worker code for importing OVF data into VirtualBox.
+ *
+ * This is called from Appliance::taskThreadImportOrExport() and therefore runs
+ * on the OVF import worker thread. This creates one or more new machines
+ * according to the VirtualSystemScription instances created by
+ * Appliance::Interpret().
*
* This runs in three contexts:
*
@@ -1162,8 +1440,8 @@ HRESULT Appliance::importImpl(const LocationInfo &locInfo,
* 3) in a second worker thread; in that case, Appliance::ImportMachines() called Appliance::importImpl(), which
* called Appliance::importS3(), which called Appliance::importImpl(), which then called this again.
*
- * @param pTask
- * @return
+ * @param pTask The OVF task data.
+ * @return COM status code.
*/
HRESULT Appliance::importFS(TaskOVF *pTask)
{
@@ -1199,6 +1477,7 @@ HRESULT Appliance::importFS(TaskOVF *pTask)
/* With _whatever_ error we've had, do a complete roll-back of
* machines and disks we've created */
writeLock.release();
+ ErrorInfoKeeper eik;
for (list<Guid>::iterator itID = m->llGuidsMachinesCreated.begin();
itID != m->llGuidsMachinesCreated.end();
++itID)
@@ -1212,7 +1491,7 @@ HRESULT Appliance::importFS(TaskOVF *pTask)
SafeIfaceArray<IMedium> aMedia;
rc2 = failedMachine->Unregister(CleanupMode_DetachAllReturnHardDisksOnly, ComSafeArrayAsOutParam(aMedia));
ComPtr<IProgress> pProgress2;
- rc2 = failedMachine->Delete(ComSafeArrayAsInParam(aMedia), pProgress2.asOutParam());
+ rc2 = failedMachine->DeleteConfig(ComSafeArrayAsInParam(aMedia), pProgress2.asOutParam());
pProgress2->WaitForCompletion(-1);
}
}
@@ -1237,6 +1516,7 @@ HRESULT Appliance::importFSOVF(TaskOVF *pTask, AutoWriteLockBase& writeLock)
PVDINTERFACEIO pShaIo = NULL;
PVDINTERFACEIO pFileIo = NULL;
void *pvMfBuf = NULL;
+ void *pvCertBuf = NULL;
writeLock.release();
try
{
@@ -1246,39 +1526,69 @@ HRESULT Appliance::importFSOVF(TaskOVF *pTask, AutoWriteLockBase& writeLock)
throw setError(E_OUTOFMEMORY);
Utf8Str strMfFile = Utf8Str(pTask->locInfo.strPath).stripExt().append(".mf");
+
+ SHASTORAGE storage;
+ RT_ZERO(storage);
+
+ Utf8Str name = applianceIOName(applianceIOFile);
+
+ int vrc = VDInterfaceAdd(&pFileIo->Core, name.c_str(),
+ VDINTERFACETYPE_IO, 0, sizeof(VDINTERFACEIO),
+ &storage.pVDImageIfaces);
+ if (RT_FAILURE(vrc))
+ throw setError(VBOX_E_IPRT_ERROR, "Creation of the VD interface failed (%Rrc)", vrc);
+
/* Create the import stack for the rollback on errors. */
ImportStack stack(pTask->locInfo, m->pReader->m_mapDisks, pTask->pProgress);
if (RTFileExists(strMfFile.c_str()))
{
- SHASTORAGE storage;
- RT_ZERO(storage);
-
pShaIo = ShaCreateInterface();
if (!pShaIo)
throw setError(E_OUTOFMEMORY);
+ Utf8Str nameSha = applianceIOName(applianceIOSha);
+ /* Fill out interface descriptor. */
+ pShaIo->Core.u32Magic = VDINTERFACE_MAGIC;
+ pShaIo->Core.cbSize = sizeof(VDINTERFACEIO);
+ pShaIo->Core.pszInterfaceName = nameSha.c_str();
+ pShaIo->Core.enmInterface = VDINTERFACETYPE_IO;
+ pShaIo->Core.pvUser = &storage;
+ pShaIo->Core.pNext = NULL;
+
storage.fCreateDigest = true;
- int vrc = VDInterfaceAdd(&pFileIo->Core, "Appliance::IOFile",
- VDINTERFACETYPE_IO, 0, sizeof(VDINTERFACEIO),
- &storage.pVDImageIfaces);
- if (RT_FAILURE(vrc))
- throw setError(VBOX_E_IPRT_ERROR, "Creation of the VD interface failed (%Rrc)", vrc);
size_t cbMfSize = 0;
- storage.fCreateDigest = true;
+
/* Now import the appliance. */
importMachines(stack, pShaIo, &storage);
/* Read & verify the manifest file. */
/* Add the ovf file to the digest list. */
stack.llSrcDisksDigest.push_front(STRPAIR(pTask->locInfo.strPath, m->strOVFSHADigest));
- rc = readManifestFile(strMfFile, &pvMfBuf, &cbMfSize, pShaIo, &storage);
+ rc = readFileToBuf(strMfFile, &pvMfBuf, &cbMfSize, true, pShaIo, &storage);
if (FAILED(rc)) throw rc;
rc = verifyManifestFile(strMfFile, stack, pvMfBuf, cbMfSize);
if (FAILED(rc)) throw rc;
+
+ size_t cbCertSize = 0;
+
+ /* Save the SHA digest of the manifest file for the next validation */
+ Utf8Str manifestShaDigest = storage.strDigest;
+
+ Utf8Str strCertFile = Utf8Str(pTask->locInfo.strPath).stripExt().append(".cert");
+ if (RTFileExists(strCertFile.c_str()))
+ {
+ rc = readFileToBuf(strCertFile, &pvCertBuf, &cbCertSize, false, pShaIo, &storage);
+ if (FAILED(rc)) throw rc;
+
+ /* verify Certificate */
+ }
}
else
- importMachines(stack, pFileIo, NULL);
+ {
+ storage.fCreateDigest = false;
+ importMachines(stack, pFileIo, &storage);
+ }
}
catch (HRESULT rc2)
{
@@ -1289,6 +1599,8 @@ HRESULT Appliance::importFSOVF(TaskOVF *pTask, AutoWriteLockBase& writeLock)
/* Cleanup */
if (pvMfBuf)
RTMemFree(pvMfBuf);
+ if (pvCertBuf)
+ RTMemFree(pvCertBuf);
if (pShaIo)
RTMemFree(pShaIo);
if (pFileIo)
@@ -1305,7 +1617,9 @@ HRESULT Appliance::importFSOVA(TaskOVF *pTask, AutoWriteLockBase& writeLock)
LogFlowFuncEnter();
RTTAR tar;
- int vrc = RTTarOpen(&tar, pTask->locInfo.strPath.c_str(), RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, true);
+ int vrc = RTTarOpen(&tar,
+ pTask->locInfo.strPath.c_str(),
+ RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, true);
if (RT_FAILURE(vrc))
return setError(VBOX_E_FILE_ERROR,
tr("Could not open OVA file '%s' (%Rrc)"),
@@ -1317,6 +1631,9 @@ HRESULT Appliance::importFSOVA(TaskOVF *pTask, AutoWriteLockBase& writeLock)
PVDINTERFACEIO pTarIo = 0;
char *pszFilename = 0;
void *pvMfBuf = 0;
+ void *pvCertBuf = 0;
+ Utf8Str OVFfilename;
+
writeLock.release();
try
{
@@ -1330,25 +1647,66 @@ HRESULT Appliance::importFSOVA(TaskOVF *pTask, AutoWriteLockBase& writeLock)
SHASTORAGE storage;
RT_ZERO(storage);
- vrc = VDInterfaceAdd(&pTarIo->Core, "Appliance::IOTar",
+
+ Utf8Str nameTar = applianceIOName(applianceIOTar);
+
+ vrc = VDInterfaceAdd(&pTarIo->Core, nameTar.c_str(),
VDINTERFACETYPE_IO, tar, sizeof(VDINTERFACEIO),
&storage.pVDImageIfaces);
if (RT_FAILURE(vrc))
throw setError(VBOX_E_IPRT_ERROR,
tr("Creation of the VD interface failed (%Rrc)"), vrc);
+ Utf8Str nameSha = applianceIOName(applianceIOSha);
+ /* Fill out interface descriptor. */
+ pShaIo->Core.u32Magic = VDINTERFACE_MAGIC;
+ pShaIo->Core.cbSize = sizeof(VDINTERFACEIO);
+ pShaIo->Core.pszInterfaceName = nameSha.c_str();
+ pShaIo->Core.enmInterface = VDINTERFACETYPE_IO;
+ pShaIo->Core.pvUser = &storage;
+ pShaIo->Core.pNext = NULL;
+
/* Read the file name of the first file (need to be the ovf file). This
* is how all internal files are named. */
vrc = RTTarCurrentFile(tar, &pszFilename);
if (RT_FAILURE(vrc))
throw setError(VBOX_E_IPRT_ERROR,
- tr("Getting the current file within the archive failed (%Rrc)"), vrc);
+ tr("Getting the OVF file within the archive failed (%Rrc)"), vrc);
+ else
+ {
+ if (vrc == VINF_TAR_DIR_PATH)
+ {
+ throw setError(VBOX_E_FILE_ERROR,
+ tr("Empty directory folder (%s) isn't allowed in the OVA package (%Rrc)"),
+ pszFilename,
+ vrc);
+ }
+ }
+
+ /* save original OVF filename */
+ OVFfilename = pszFilename;
+ size_t cbMfSize = 0;
+ size_t cbCertSize = 0;
+ Utf8Str strMfFile = (Utf8Str(pszFilename)).stripExt().append(".mf");
+ Utf8Str strCertFile = (Utf8Str(pszFilename)).stripExt().append(".cert");
+
/* Skip the OVF file, cause this was read in IAppliance::Read already. */
vrc = RTTarSeekNextFile(tar);
if ( RT_FAILURE(vrc)
&& vrc != VERR_TAR_END_OF_FILE)
throw setError(VBOX_E_IPRT_ERROR,
tr("Seeking within the archive failed (%Rrc)"), vrc);
+ else
+ {
+ RTTarCurrentFile(tar, &pszFilename);
+ if (vrc == VINF_TAR_DIR_PATH)
+ {
+ throw setError(VBOX_E_FILE_ERROR,
+ tr("Empty directory folder (%s) isn't allowed in the OVA package (%Rrc)"),
+ pszFilename,
+ vrc);
+ }
+ }
PVDINTERFACEIO pCallbacks = pShaIo;
PSHASTORAGE pStorage = &storage;
@@ -1357,8 +1715,6 @@ HRESULT Appliance::importFSOVA(TaskOVF *pTask, AutoWriteLockBase& writeLock)
* is a manifest file in the stream. */
pStorage->fCreateDigest = true;
- size_t cbMfSize = 0;
- Utf8Str strMfFile = Utf8Str(pszFilename).stripExt().append(".mf");
/* Create the import stack for the rollback on errors. */
ImportStack stack(pTask->locInfo, m->pReader->m_mapDisks, pTask->pProgress);
/*
@@ -1373,23 +1729,68 @@ HRESULT Appliance::importFSOVA(TaskOVF *pTask, AutoWriteLockBase& writeLock)
* searching for it. We have to try to open it on all possible places.
* If it fails here, we will try it again after all disks where read.
*/
- rc = readTarManifestFile(tar, strMfFile, &pvMfBuf, &cbMfSize, pCallbacks, pStorage);
+ rc = readTarFileToBuf(tar, strMfFile, &pvMfBuf, &cbMfSize, true, pCallbacks, pStorage);
if (FAILED(rc)) throw rc;
+
+ /*
+ * Try to read the certificate file. First try.
+ * Logic is the same as with manifest file
+ * Only if the manifest file had been read successfully before
+ */
+ vrc = RTTarCurrentFile(tar, &pszFilename);
+ if (RT_SUCCESS(vrc))
+ {
+ if (pvMfBuf)
+ {
+ if (strCertFile.compare(pszFilename) == 0)
+ {
+ rc = readTarFileToBuf(tar, strCertFile, &pvCertBuf, &cbCertSize, false, pCallbacks, pStorage);
+ if (FAILED(rc)) throw rc;
+
+ if (pvCertBuf)
+ {
+ /* verify the certificate */
+ }
+ }
+ }
+ }
+
/* Now import the appliance. */
importMachines(stack, pCallbacks, pStorage);
/* Try to read the manifest file. Second try. */
if (!pvMfBuf)
{
- rc = readTarManifestFile(tar, strMfFile, &pvMfBuf, &cbMfSize, pCallbacks, pStorage);
- if (FAILED(rc)) throw rc;
- }
- /* If we were able to read a manifest file we can check it now. */
- if (pvMfBuf)
- {
- /* Add the ovf file to the digest list. */
- stack.llSrcDisksDigest.push_front(STRPAIR(Utf8Str(pszFilename).stripExt().append(".ovf"), m->strOVFSHADigest));
- rc = verifyManifestFile(strMfFile, stack, pvMfBuf, cbMfSize);
+ rc = readTarFileToBuf(tar, strMfFile, &pvMfBuf, &cbMfSize, true, pCallbacks, pStorage);
if (FAILED(rc)) throw rc;
+
+ /* If we were able to read a manifest file we can check it now. */
+ if (pvMfBuf)
+ {
+ /* Add the ovf file to the digest list. */
+ stack.llSrcDisksDigest.push_front(STRPAIR(OVFfilename, m->strOVFSHADigest));
+ rc = verifyManifestFile(strMfFile, stack, pvMfBuf, cbMfSize);
+ if (FAILED(rc)) throw rc;
+
+ /*
+ * Try to read the certificate file. Second try.
+ * Only if the manifest file had been read successfully before
+ */
+
+ vrc = RTTarCurrentFile(tar, &pszFilename);
+ if (RT_SUCCESS(vrc))
+ {
+ if (strCertFile.compare(pszFilename) == 0)
+ {
+ rc = readTarFileToBuf(tar, strCertFile, &pvCertBuf, &cbCertSize, false, pCallbacks, pStorage);
+ if (FAILED(rc)) throw rc;
+
+ if (pvCertBuf)
+ {
+ /* verify the certificate */
+ }
+ }
+ }
+ }
}
}
catch (HRESULT rc2)
@@ -1409,6 +1810,8 @@ HRESULT Appliance::importFSOVA(TaskOVF *pTask, AutoWriteLockBase& writeLock)
RTMemFree(pShaIo);
if (pTarIo)
RTMemFree(pTarIo);
+ if (pvCertBuf)
+ RTMemFree(pvCertBuf);
LogFlowFunc(("rc=%Rhrc\n", rc));
LogFlowFuncLeave();
@@ -1481,7 +1884,11 @@ HRESULT Appliance::importS3(TaskOVF *pTask)
}
/* Next we have to download the disk images */
- vrc = RTS3Create(&hS3, pTask->locInfo.strUsername.c_str(), pTask->locInfo.strPassword.c_str(), pTask->locInfo.strHostname.c_str(), "virtualbox-agent/"VBOX_VERSION_STRING);
+ vrc = RTS3Create(&hS3,
+ pTask->locInfo.strUsername.c_str(),
+ pTask->locInfo.strPassword.c_str(),
+ pTask->locInfo.strHostname.c_str(),
+ "virtualbox-agent/"VBOX_VERSION_STRING);
if (RT_FAILURE(vrc))
throw setError(VBOX_E_IPRT_ERROR,
tr("Cannot create S3 service handler"));
@@ -1506,7 +1913,8 @@ HRESULT Appliance::importS3(TaskOVF *pTask)
else if (vrc == VERR_S3_ACCESS_DENIED)
throw setError(E_ACCESSDENIED,
tr("Cannot download file '%s' from S3 storage server (Access denied). "
- "Make sure that your credentials are right. Also check that your host clock is properly synced"),
+ "Make sure that your credentials are right. Also check that your host clock is "
+ "properly synced"),
pszFilename);
else if (vrc == VERR_S3_NOT_FOUND)
throw setError(VBOX_E_FILE_ERROR,
@@ -1542,7 +1950,8 @@ HRESULT Appliance::importS3(TaskOVF *pTask)
else if (vrc == VERR_S3_ACCESS_DENIED)
throw setError(E_ACCESSDENIED,
tr("Cannot download file '%s' from S3 storage server (Access denied)."
- "Make sure that your credentials are right. Also check that your host clock is properly synced"),
+ "Make sure that your credentials are right. "
+ "Also check that your host clock is properly synced"),
pszFilename);
else
throw setError(VBOX_E_IPRT_ERROR,
@@ -1609,24 +2018,35 @@ HRESULT Appliance::importS3(TaskOVF *pTask)
}
#endif /* VBOX_WITH_S3 */
-HRESULT Appliance::readManifestFile(const Utf8Str &strFile, void **ppvBuf, size_t *pcbSize, PVDINTERFACEIO pCallbacks, PSHASTORAGE pStorage)
+HRESULT Appliance::readFileToBuf(const Utf8Str &strFile,
+ void **ppvBuf,
+ size_t *pcbSize,
+ bool fCreateDigest,
+ PVDINTERFACEIO pCallbacks,
+ PSHASTORAGE pStorage)
{
HRESULT rc = S_OK;
- bool fOldDigest = pStorage->fCreateDigest;
- pStorage->fCreateDigest = false; /* No digest for the manifest file */
+ bool fOldDigest = pStorage->fCreateDigest;/* Save the old digest property */
+ pStorage->fCreateDigest = fCreateDigest;
int vrc = ShaReadBuf(strFile.c_str(), ppvBuf, pcbSize, pCallbacks, pStorage);
if ( RT_FAILURE(vrc)
&& vrc != VERR_FILE_NOT_FOUND)
rc = setError(VBOX_E_FILE_ERROR,
- tr("Could not read manifest file '%s' (%Rrc)"),
+ tr("Could not read file '%s' (%Rrc)"),
RTPathFilename(strFile.c_str()), vrc);
pStorage->fCreateDigest = fOldDigest; /* Restore the old digest creation behavior again. */
return rc;
}
-HRESULT Appliance::readTarManifestFile(RTTAR tar, const Utf8Str &strFile, void **ppvBuf, size_t *pcbSize, PVDINTERFACEIO pCallbacks, PSHASTORAGE pStorage)
+HRESULT Appliance::readTarFileToBuf(RTTAR tar,
+ const Utf8Str &strFile,
+ void **ppvBuf,
+ size_t *pcbSize,
+ bool fCreateDigest,
+ PVDINTERFACEIO pCallbacks,
+ PSHASTORAGE pStorage)
{
HRESULT rc = S_OK;
@@ -1634,9 +2054,19 @@ HRESULT Appliance::readTarManifestFile(RTTAR tar, const Utf8Str &strFile, void *
int vrc = RTTarCurrentFile(tar, &pszCurFile);
if (RT_SUCCESS(vrc))
{
- if (!strcmp(pszCurFile, RTPathFilename(strFile.c_str())))
- rc = readManifestFile(strFile, ppvBuf, pcbSize, pCallbacks, pStorage);
- RTStrFree(pszCurFile);
+ if (vrc == VINF_TAR_DIR_PATH)
+ {
+ rc = setError(VBOX_E_FILE_ERROR,
+ tr("Empty directory folder (%s) isn't allowed in the OVA package (%Rrc)"),
+ pszCurFile,
+ vrc);
+ }
+ else
+ {
+ if (!strcmp(pszCurFile, RTPathFilename(strFile.c_str())))
+ rc = readFileToBuf(strFile, ppvBuf, pcbSize, fCreateDigest, pCallbacks, pStorage);
+ RTStrFree(pszCurFile);
+ }
}
else if (vrc != VERR_TAR_END_OF_FILE)
rc = setError(VBOX_E_IPRT_ERROR, "Seeking within the archive failed (%Rrc)", vrc);
@@ -1665,7 +2095,7 @@ HRESULT Appliance::verifyManifestFile(const Utf8Str &strFile, ImportStack &stack
int vrc = RTManifestVerifyFilesBuf(pvBuf, cbSize, paTests, stack.llSrcDisksDigest.size(), &iFailed);
if (RT_UNLIKELY(vrc == VERR_MANIFEST_DIGEST_MISMATCH))
rc = setError(VBOX_E_FILE_ERROR,
- tr("The SHA1 digest of '%s' does not match the one in '%s' (%Rrc)"),
+ tr("The SHA digest of '%s' does not match the one in '%s' (%Rrc)"),
RTPathFilename(paTests[iFailed].pszTestFile), RTPathFilename(strFile.c_str()), vrc);
else if (RT_FAILURE(vrc))
rc = setError(VBOX_E_FILE_ERROR,
@@ -1677,7 +2107,6 @@ HRESULT Appliance::verifyManifestFile(const Utf8Str &strFile, ImportStack &stack
return rc;
}
-
/**
* Helper that converts VirtualSystem attachment values into VirtualBox attachment values.
* Throws HRESULT values on errors!
@@ -1694,7 +2123,10 @@ void Appliance::convertDiskAttachmentValues(const ovf::HardDiskController &hdc,
int32_t &lControllerPort,
int32_t &lDevice)
{
- Log(("Appliance::convertDiskAttachmentValues: hdc.system=%d, hdc.fPrimary=%d, ulAddressOnParent=%d\n", hdc.system, hdc.fPrimary, ulAddressOnParent));
+ Log(("Appliance::convertDiskAttachmentValues: hdc.system=%d, hdc.fPrimary=%d, ulAddressOnParent=%d\n",
+ hdc.system,
+ hdc.fPrimary,
+ ulAddressOnParent));
switch (hdc.system)
{
@@ -1790,31 +2222,57 @@ void Appliance::convertDiskAttachmentValues(const ovf::HardDiskController &hdc,
* This advances stack.pProgress by one operation with the disk's weight.
*
* @param di ovfreader.cpp structure describing the disk image from the OVF that is to be imported
- * @param ulSizeMB Size of the disk image (for progress reporting)
* @param strTargetPath Where to create the target image.
* @param pTargetHD out: The newly created target disk. This also gets pushed on stack.llHardDisksCreated for cleanup.
* @param stack
*/
void Appliance::importOneDiskImage(const ovf::DiskImage &di,
- const Utf8Str &strTargetPath,
+ Utf8Str *strTargetPath,
ComObjPtr<Medium> &pTargetHD,
ImportStack &stack,
PVDINTERFACEIO pCallbacks,
PSHASTORAGE pStorage)
{
+ SHASTORAGE finalStorage;
+ PSHASTORAGE pRealUsedStorage = pStorage;/* may be changed later to finalStorage */
+ PVDINTERFACEIO pFileIo = NULL;/* used in GZIP case*/
ComObjPtr<Progress> pProgress;
pProgress.createObject();
- HRESULT rc = pProgress->init(mVirtualBox, static_cast<IAppliance*>(this), BstrFmt(tr("Creating medium '%s'"), strTargetPath.c_str()).raw(), TRUE);
+ HRESULT rc = pProgress->init(mVirtualBox,
+ static_cast<IAppliance*>(this),
+ BstrFmt(tr("Creating medium '%s'"),
+ strTargetPath->c_str()).raw(),
+ TRUE);
if (FAILED(rc)) throw rc;
/* Get the system properties. */
SystemProperties *pSysProps = mVirtualBox->getSystemProperties();
+ /*
+ * we put strSourceOVF into the stack.llSrcDisksDigest in the end of this
+ * function like a key for a later validation of the SHA digests
+ */
+ const Utf8Str &strSourceOVF = di.strHref;
+
+ Utf8Str strSrcFilePath(stack.strSourceDir);
+ Utf8Str strTargetDir(*strTargetPath);
+
+ /* Construct source file path */
+ Utf8Str name = applianceIOName(applianceIOTar);
+
+ if (RTStrNICmp(pStorage->pVDImageIfaces->pszInterfaceName, name.c_str(), name.length()) == 0)
+ strSrcFilePath = strSourceOVF;
+ else
+ {
+ strSrcFilePath.append(RTPATH_SLASH_STR);
+ strSrcFilePath.append(strSourceOVF);
+ }
+
/* First of all check if the path is an UUID. If so, the user like to
* import the disk into an existing path. This is useful for iSCSI for
* example. */
RTUUID uuid;
- int vrc = RTUuidFromStr(&uuid, strTargetPath.c_str());
+ int vrc = RTUuidFromStr(&uuid, strTargetPath->c_str());
if (vrc == VINF_SUCCESS)
{
rc = mVirtualBox->findHardDiskById(Guid(uuid), true, &pTargetHD);
@@ -1822,102 +2280,248 @@ void Appliance::importOneDiskImage(const ovf::DiskImage &di,
}
else
{
- Utf8Str strTrgFormat = "VMDK";
- if (RTPathHaveExt(strTargetPath.c_str()))
+ bool fGzipUsed = !(di.strCompression.compare("gzip",Utf8Str::CaseInsensitive));
+ /* check read file to GZIP compression */
+ try
{
- char *pszExt = RTPathExt(strTargetPath.c_str());
- /* Figure out which format the user like to have. Default is VMDK. */
- ComObjPtr<MediumFormat> trgFormat = pSysProps->mediumFormatFromExtension(&pszExt[1]);
- if (trgFormat.isNull())
- throw setError(VBOX_E_NOT_SUPPORTED,
- tr("Could not find a valid medium format for the target disk '%s'"),
- strTargetPath.c_str());
- /* Check the capabilities. We need create capabilities. */
+ if (fGzipUsed == true)
+ {
+ /*
+ * Create the necessary file access interfaces.
+ * For the next step:
+ * We need to replace the previously created chain of SHA-TAR or SHA-FILE interfaces
+ * with simple FILE interface because we don't need SHA or TAR interfaces here anymore.
+ * But we mustn't delete the chain of SHA-TAR or SHA-FILE interfaces.
+ */
+
+ /* Decompress the GZIP file and save a new file in the target path */
+ strTargetDir = strTargetDir.stripFilename();
+ strTargetDir.append("/temp_");
+
+ Utf8Str strTempTargetFilename(*strTargetPath);
+ strTempTargetFilename = strTempTargetFilename.stripPath();
+ strTempTargetFilename = strTempTargetFilename.stripExt();
+ Utf8Str vdf = typeOfVirtualDiskFormatFromURI(di.strFormat);
+
+ strTargetDir.append(strTempTargetFilename);
+
+ vrc = decompressImageAndSave(strSrcFilePath.c_str(), strTargetDir.c_str(), pCallbacks, pStorage);
+
+ if (RT_FAILURE(vrc))
+ throw setError(VBOX_E_FILE_ERROR,
+ tr("Could not read the file '%s' (%Rrc)"),
+ RTPathFilename(strSrcFilePath.c_str()), vrc);
+
+ /* Create the necessary file access interfaces. */
+ pFileIo = FileCreateInterface();
+ if (!pFileIo)
+ throw setError(E_OUTOFMEMORY);
+
+ name = applianceIOName(applianceIOFile);
+
+ vrc = VDInterfaceAdd(&pFileIo->Core, name.c_str(),
+ VDINTERFACETYPE_IO, NULL, sizeof(VDINTERFACEIO),
+ &finalStorage.pVDImageIfaces);
+ if (RT_FAILURE(vrc))
+ throw setError(VBOX_E_IPRT_ERROR,
+ tr("Creation of the VD interface failed (%Rrc)"), vrc);
+
+ /* Correct the source and the target with the actual values */
+ strSrcFilePath = strTargetDir;
+ strTargetDir = strTargetDir.stripFilename();
+ strTargetDir.append(RTPATH_SLASH_STR);
+ strTargetDir.append(strTempTargetFilename.c_str());
+ *strTargetPath = strTargetDir.c_str();
+
+ pRealUsedStorage = &finalStorage;
+ }
+
+ Utf8Str strTrgFormat = "VMDK";
ULONG lCabs = 0;
- rc = trgFormat->COMGETTER(Capabilities)(&lCabs);
- if (FAILED(rc)) throw rc;
- if (!( ((lCabs & MediumFormatCapabilities_CreateFixed) == MediumFormatCapabilities_CreateFixed)
- || ((lCabs & MediumFormatCapabilities_CreateDynamic) == MediumFormatCapabilities_CreateDynamic)))
- throw setError(VBOX_E_NOT_SUPPORTED,
- tr("Could not find a valid medium format for the target disk '%s'"),
- strTargetPath.c_str());
- Bstr bstrFormatName;
- rc = trgFormat->COMGETTER(Name)(bstrFormatName.asOutParam());
- if (FAILED(rc)) throw rc;
- strTrgFormat = Utf8Str(bstrFormatName);
- }
+ char *pszExt = NULL;
- /* Create an IMedium object. */
- pTargetHD.createObject();
- rc = pTargetHD->init(mVirtualBox,
- strTrgFormat,
- strTargetPath,
- Guid::Empty /* media registry: none yet */);
- if (FAILED(rc)) throw rc;
+ if (RTPathHaveExt(strTargetPath->c_str()))
+ {
+ pszExt = RTPathExt(strTargetPath->c_str());
+ /* Figure out which format the user like to have. Default is VMDK. */
+ ComObjPtr<MediumFormat> trgFormat = pSysProps->mediumFormatFromExtension(&pszExt[1]);
+ if (trgFormat.isNull())
+ throw setError(VBOX_E_NOT_SUPPORTED,
+ tr("Could not find a valid medium format for the target disk '%s'"),
+ strTargetPath->c_str());
+ /* Check the capabilities. We need create capabilities. */
+ lCabs = 0;
+ com::SafeArray <MediumFormatCapabilities_T> mediumFormatCap;
+ rc = trgFormat->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(mediumFormatCap));
+
+ if (FAILED(rc))
+ throw rc;
+ else
+ {
+ for (ULONG j = 0; j < mediumFormatCap.size(); j++)
+ lCabs |= mediumFormatCap[j];
+ }
- /* Now create an empty hard disk. */
- rc = mVirtualBox->CreateHardDisk(NULL,
- Bstr(strTargetPath).raw(),
- ComPtr<IMedium>(pTargetHD).asOutParam());
- if (FAILED(rc)) throw rc;
- }
+ if (!( ((lCabs & MediumFormatCapabilities_CreateFixed) == MediumFormatCapabilities_CreateFixed)
+ || ((lCabs & MediumFormatCapabilities_CreateDynamic) == MediumFormatCapabilities_CreateDynamic)))
+ throw setError(VBOX_E_NOT_SUPPORTED,
+ tr("Could not find a valid medium format for the target disk '%s'"),
+ strTargetPath->c_str());
+ Bstr bstrFormatName;
+ rc = trgFormat->COMGETTER(Name)(bstrFormatName.asOutParam());
+ if (FAILED(rc)) throw rc;
+ strTrgFormat = Utf8Str(bstrFormatName);
+ }
+ else
+ {
+ throw setError(VBOX_E_FILE_ERROR,
+ tr("The target disk '%s' has no extension "),
+ strTargetPath->c_str(), VERR_INVALID_NAME);
+ }
- const Utf8Str &strSourceOVF = di.strHref;
- /* Construct source file path */
- Utf8StrFmt strSrcFilePath("%s%c%s", stack.strSourceDir.c_str(), RTPATH_DELIMITER, strSourceOVF.c_str());
+ /* Create an IMedium object. */
+ pTargetHD.createObject();
- /* If strHref is empty we have to create a new file. */
- if (strSourceOVF.isEmpty())
- {
- /* Create a dynamic growing disk image with the given capacity. */
- rc = pTargetHD->CreateBaseStorage(di.iCapacity / _1M, MediumVariant_Standard, ComPtr<IProgress>(pProgress).asOutParam());
- if (FAILED(rc)) throw rc;
+ /*CD/DVD case*/
+ if (strTrgFormat.compare("RAW", Utf8Str::CaseInsensitive) == 0)
+ {
+ try
+ {
+ if (fGzipUsed == true)
+ {
+ /*
+ * The source and target pathes are the same.
+ * It means that we have the needed file already.
+ * For example, in GZIP case, we decompress the file and save it in the target path,
+ * but with some prefix like "temp_". See part "check read file to GZIP compression" earlier
+ * in this function.
+ * Just rename the file by deleting "temp_" from it's name
+ */
+ vrc = RTFileRename(strSrcFilePath.c_str(), strTargetPath->c_str(), RTPATHRENAME_FLAGS_NO_REPLACE);
+ if (RT_FAILURE(vrc))
+ throw setError(VBOX_E_FILE_ERROR,
+ tr("Could not rename the file '%s' (%Rrc)"),
+ RTPathFilename(strSourceOVF.c_str()), vrc);
+ }
+ else
+ {
+ /* Calculating SHA digest for ISO file while copying one */
+ vrc = copyFileAndCalcShaDigest(strSrcFilePath.c_str(),
+ strTargetPath->c_str(),
+ pCallbacks,
+ pRealUsedStorage);
+
+ if (RT_FAILURE(vrc))
+ throw setError(VBOX_E_FILE_ERROR,
+ tr("Could not copy ISO file '%s' listed in the OVF file (%Rrc)"),
+ RTPathFilename(strSourceOVF.c_str()), vrc);
+ }
+ }
+ catch (HRESULT /*arc*/)
+ {
+ throw;
+ }
- /* Advance to the next operation. */
- stack.pProgress->SetNextOperation(BstrFmt(tr("Creating disk image '%s'"), strTargetPath.c_str()).raw(),
- di.ulSuggestedSizeMB); // operation's weight, as set up with the IProgress originally
- }
- else
- {
- /* We need a proper source format description */
- ComObjPtr<MediumFormat> srcFormat;
- /* Which format to use? */
- Utf8Str strSrcFormat = "VDI";
- if ( di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#sparse", Utf8Str::CaseInsensitive)
- || di.strFormat.compare("http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized", Utf8Str::CaseInsensitive)
- || di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#compressed", Utf8Str::CaseInsensitive)
- || di.strFormat.compare("http://www.vmware.com/interfaces/specifications/vmdk.html#compressed", Utf8Str::CaseInsensitive)
- )
- strSrcFormat = "VMDK";
- srcFormat = pSysProps->mediumFormat(strSrcFormat);
- if (srcFormat.isNull())
- throw setError(VBOX_E_NOT_SUPPORTED,
- tr("Could not find a valid medium format for the source disk '%s'"),
- RTPathFilename(strSrcFilePath.c_str()));
-
- /* Clone the source disk image */
- ComObjPtr<Medium> nullParent;
- rc = pTargetHD->importFile(strSrcFilePath.c_str(),
- srcFormat,
- MediumVariant_Standard,
- pCallbacks, pStorage,
- nullParent,
- pProgress);
- if (FAILED(rc)) throw rc;
+ /* Advance to the next operation. */
+ /* operation's weight, as set up with the IProgress originally */
+ stack.pProgress->SetNextOperation(BstrFmt(tr("Importing virtual disk image '%s'"),
+ RTPathFilename(strSourceOVF.c_str())).raw(),
+ di.ulSuggestedSizeMB);
+ }
+ else/* HDD case*/
+ {
+ rc = pTargetHD->init(mVirtualBox,
+ strTrgFormat,
+ *strTargetPath,
+ Guid::Empty /* media registry: none yet */);
+ if (FAILED(rc)) throw rc;
- /* Advance to the next operation. */
- stack.pProgress->SetNextOperation(BstrFmt(tr("Importing virtual disk image '%s'"), RTPathFilename(strSrcFilePath.c_str())).raw(),
- di.ulSuggestedSizeMB); // operation's weight, as set up with the IProgress originally);
+ /* Now create an empty hard disk. */
+ rc = mVirtualBox->CreateHardDisk(Bstr(strTrgFormat).raw(),
+ Bstr(*strTargetPath).raw(),
+ ComPtr<IMedium>(pTargetHD).asOutParam());
+ if (FAILED(rc)) throw rc;
+
+ /* If strHref is empty we have to create a new file. */
+ if (strSourceOVF.isEmpty())
+ {
+ com::SafeArray<MediumVariant_T> mediumVariant;
+ mediumVariant.push_back(MediumVariant_Standard);
+ /* Create a dynamic growing disk image with the given capacity. */
+ rc = pTargetHD->CreateBaseStorage(di.iCapacity / _1M,
+ ComSafeArrayAsInParam(mediumVariant),
+ ComPtr<IProgress>(pProgress).asOutParam());
+ if (FAILED(rc)) throw rc;
+
+ /* Advance to the next operation. */
+ /* operation's weight, as set up with the IProgress originally */
+ stack.pProgress->SetNextOperation(BstrFmt(tr("Creating disk image '%s'"),
+ strTargetPath->c_str()).raw(),
+ di.ulSuggestedSizeMB);
+ }
+ else
+ {
+ /* We need a proper source format description */
+ /* Which format to use? */
+ Utf8Str strSrcFormat = typeOfVirtualDiskFormatFromURI(di.strFormat);
+
+ ComObjPtr<MediumFormat> srcFormat = pSysProps->mediumFormat(strSrcFormat);
+ if (srcFormat.isNull())
+ throw setError(VBOX_E_NOT_SUPPORTED,
+ tr("Could not find a valid medium format for the source disk '%s' "
+ "Check correctness of the image format URL in the OVF description file."),
+ RTPathFilename(strSourceOVF.c_str()));
+
+ /* Clone the source disk image */
+ ComObjPtr<Medium> nullParent;
+ rc = pTargetHD->importFile(strSrcFilePath.c_str(),
+ srcFormat,
+ MediumVariant_Standard,
+ pCallbacks, pRealUsedStorage,
+ nullParent,
+ pProgress);
+ if (FAILED(rc)) throw rc;
+
+ /* Advance to the next operation. */
+ /* operation's weight, as set up with the IProgress originally */
+ stack.pProgress->SetNextOperation(BstrFmt(tr("Importing virtual disk image '%s'"),
+ RTPathFilename(strSourceOVF.c_str())).raw(),
+ di.ulSuggestedSizeMB);
+ }
+
+ /* Now wait for the background disk operation to complete; this throws
+ * HRESULTs on error. */
+ ComPtr<IProgress> pp(pProgress);
+ waitForAsyncProgress(stack.pProgress, pp);
+
+ if (fGzipUsed == true)
+ {
+ /*
+ * Just delete the temporary file
+ */
+ vrc = RTFileDelete(strSrcFilePath.c_str());
+ if (RT_FAILURE(vrc))
+ setWarning(VBOX_E_FILE_ERROR,
+ tr("Could not delete the file '%s' (%Rrc)"),
+ RTPathFilename(strSrcFilePath.c_str()), vrc);
+ }
+ }
+ }
+ catch (...)
+ {
+ if (pFileIo)
+ RTMemFree(pFileIo);
+
+ throw;
+ }
}
- /* Now wait for the background disk operation to complete; this throws
- * HRESULTs on error. */
- ComPtr<IProgress> pp(pProgress);
- waitForAsyncProgress(stack.pProgress, pp);
+ if (pFileIo)
+ RTMemFree(pFileIo);
/* Add the newly create disk path + a corresponding digest the our list for
* later manifest verification. */
- stack.llSrcDisksDigest.push_back(STRPAIR(strSrcFilePath, pStorage ? pStorage->strDigest : ""));
+ stack.llSrcDisksDigest.push_back(STRPAIR(strSourceOVF, pStorage ? pStorage->strDigest : ""));
}
/**
@@ -1940,6 +2544,7 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis,
PVDINTERFACEIO pCallbacks,
PSHASTORAGE pStorage)
{
+ LogFlowFuncEnter();
HRESULT rc;
// Get the instance of IGuestOSType which matches our string guest OS type so we
@@ -2027,11 +2632,12 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis,
#ifdef VBOX_WITH_USB
/* USB Controller */
- ComPtr<IUSBController> usbController;
- rc = pNewMachine->COMGETTER(USBController)(usbController.asOutParam());
- if (FAILED(rc)) throw rc;
- rc = usbController->COMSETTER(Enabled)(stack.fUSBEnabled);
- if (FAILED(rc)) throw rc;
+ if (stack.fUSBEnabled)
+ {
+ ComPtr<IUSBController> usbController;
+ rc = pNewMachine->AddUSBController(Bstr("OHCI").raw(), USBControllerType_OHCI, usbController.asOutParam());
+ if (FAILED(rc)) throw rc;
+ }
#endif /* VBOX_WITH_USB */
/* Change the network adapters */
@@ -2049,7 +2655,8 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis,
}
else if (vsdeNW.size() > maxNetworkAdapters)
throw setError(VBOX_E_FILE_ERROR,
- tr("Too many network adapters: OVF requests %d network adapters, but VirtualBox only supports %d"),
+ tr("Too many network adapters: OVF requests %d network adapters, "
+ "but VirtualBox only supports %d"),
vsdeNW.size(), maxNetworkAdapters);
else
{
@@ -2061,7 +2668,7 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis,
{
const VirtualSystemDescriptionEntry* pvsys = *nwIt;
- const Utf8Str &nwTypeVBox = pvsys->strVboxCurrent;
+ const Utf8Str &nwTypeVBox = pvsys->strVBoxCurrent;
uint32_t tt1 = RTStrToUInt32(nwTypeVBox.c_str());
ComPtr<INetworkAdapter> pNetworkAdapter;
rc = pNewMachine->GetNetworkAdapter((ULONG)a, pNetworkAdapter.asOutParam());
@@ -2099,7 +2706,7 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis,
rc = nwInterfaces[j]->COMGETTER(Name)(name.asOutParam());
if (FAILED(rc)) throw rc;
/* Set the interface name to attach to */
- pNetworkAdapter->COMSETTER(BridgedInterface)(name.raw());
+ rc = pNetworkAdapter->COMSETTER(BridgedInterface)(name.raw());
if (FAILED(rc)) throw rc;
break;
}
@@ -2132,7 +2739,7 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis,
rc = nwInterfaces[j]->COMGETTER(Name)(name.asOutParam());
if (FAILED(rc)) throw rc;
/* Set the interface name to attach to */
- pNetworkAdapter->COMSETTER(HostOnlyInterface)(name.raw());
+ rc = pNetworkAdapter->COMSETTER(HostOnlyInterface)(name.raw());
if (FAILED(rc)) throw rc;
break;
}
@@ -2152,13 +2759,37 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis,
rc = pNetworkAdapter->COMSETTER(AttachmentType)(NetworkAttachmentType_Generic);
if (FAILED(rc)) throw rc;
}
+ /* Next test for NAT network interfaces */
+ else if (pvsys->strExtraConfigCurrent.endsWith("type=NATNetwork", Utf8Str::CaseInsensitive))
+ {
+ /* Attach to the right interface */
+ rc = pNetworkAdapter->COMSETTER(AttachmentType)(NetworkAttachmentType_NATNetwork);
+ if (FAILED(rc)) throw rc;
+ com::SafeIfaceArray<INATNetwork> nwNATNetworks;
+ rc = mVirtualBox->COMGETTER(NATNetworks)(ComSafeArrayAsOutParam(nwNATNetworks));
+ if (FAILED(rc)) throw rc;
+ // Pick the first NAT network (if there is any)
+ if (nwNATNetworks.size())
+ {
+ Bstr name;
+ rc = nwNATNetworks[0]->COMGETTER(NetworkName)(name.asOutParam());
+ if (FAILED(rc)) throw rc;
+ /* Set the NAT network name to attach to */
+ rc = pNetworkAdapter->COMSETTER(NATNetwork)(name.raw());
+ if (FAILED(rc)) throw rc;
+ break;
+ }
+ }
}
}
// IDE Hard disk controller
std::list<VirtualSystemDescriptionEntry*> vsdeHDCIDE = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskControllerIDE);
- // In OVF (at least VMware's version of it), an IDE controller has two ports, so VirtualBox's single IDE controller
- // with two channels and two ports each counts as two OVF IDE controllers -- so we accept one or two such IDE controllers
+ /*
+ * In OVF (at least VMware's version of it), an IDE controller has two ports,
+ * so VirtualBox's single IDE controller with two channels and two ports each counts as
+ * two OVF IDE controllers -- so we accept one or two such IDE controllers
+ */
size_t cIDEControllers = vsdeHDCIDE.size();
if (cIDEControllers > 2)
throw setError(VBOX_E_FILE_ERROR,
@@ -2170,7 +2801,7 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis,
rc = pNewMachine->AddStorageController(Bstr("IDE Controller").raw(), StorageBus_IDE, pController.asOutParam());
if (FAILED(rc)) throw rc;
- const char *pcszIDEType = vsdeHDCIDE.front()->strVboxCurrent.c_str();
+ const char *pcszIDEType = vsdeHDCIDE.front()->strVBoxCurrent.c_str();
if (!strcmp(pcszIDEType, "PIIX3"))
rc = pController->COMSETTER(ControllerType)(StorageControllerType_PIIX3);
else if (!strcmp(pcszIDEType, "PIIX4"))
@@ -2192,10 +2823,12 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis,
if (vsdeHDCSATA.size() > 0)
{
ComPtr<IStorageController> pController;
- const Utf8Str &hdcVBox = vsdeHDCSATA.front()->strVboxCurrent;
+ const Utf8Str &hdcVBox = vsdeHDCSATA.front()->strVBoxCurrent;
if (hdcVBox == "AHCI")
{
- rc = pNewMachine->AddStorageController(Bstr("SATA Controller").raw(), StorageBus_SATA, pController.asOutParam());
+ rc = pNewMachine->AddStorageController(Bstr("SATA Controller").raw(),
+ StorageBus_SATA,
+ pController.asOutParam());
if (FAILED(rc)) throw rc;
}
else
@@ -2215,7 +2848,7 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis,
Bstr bstrName(L"SCSI Controller");
StorageBus_T busType = StorageBus_SCSI;
StorageControllerType_T controllerType;
- const Utf8Str &hdcVBox = vsdeHDCSCSI.front()->strVboxCurrent;
+ const Utf8Str &hdcVBox = vsdeHDCSCSI.front()->strVBoxCurrent;
if (hdcVBox == "LsiLogic")
controllerType = StorageControllerType_LsiLogic;
else if (hdcVBox == "LsiLogicSas")
@@ -2246,7 +2879,9 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis,
if (vsdeHDCSAS.size() > 0)
{
ComPtr<IStorageController> pController;
- rc = pNewMachine->AddStorageController(Bstr(L"SAS Controller").raw(), StorageBus_SAS, pController.asOutParam());
+ rc = pNewMachine->AddStorageController(Bstr(L"SAS Controller").raw(),
+ StorageBus_SAS,
+ pController.asOutParam());
if (FAILED(rc)) throw rc;
rc = pController->COMSETTER(ControllerType)(StorageControllerType_LsiLogicSas);
if (FAILED(rc)) throw rc;
@@ -2291,7 +2926,9 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis,
if (vsdeFloppy.size() == 1)
{
ComPtr<IStorageController> pController;
- rc = sMachine->AddStorageController(Bstr("Floppy Controller").raw(), StorageBus_Floppy, pController.asOutParam());
+ rc = sMachine->AddStorageController(Bstr("Floppy Controller").raw(),
+ StorageBus_Floppy,
+ pController.asOutParam());
if (FAILED(rc)) throw rc;
Bstr bstrName;
@@ -2317,54 +2954,6 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis,
stack.llHardDiskAttachments.push_back(mhda);
}
- // CD-ROMs next
- for (std::list<VirtualSystemDescriptionEntry*>::const_iterator jt = vsdeCDROM.begin();
- jt != vsdeCDROM.end();
- ++jt)
- {
- // for now always attach to secondary master on IDE controller;
- // there seems to be no useful information in OVF where else to
- // attach it (@todo test with latest versions of OVF software)
-
- // find the IDE controller
- const ovf::HardDiskController *pController = NULL;
- for (ovf::ControllersMap::const_iterator kt = vsysThis.mapControllers.begin();
- kt != vsysThis.mapControllers.end();
- ++kt)
- {
- if (kt->second.system == ovf::HardDiskController::IDE)
- {
- pController = &kt->second;
- break;
- }
- }
-
- if (!pController)
- throw setError(VBOX_E_FILE_ERROR,
- tr("OVF wants a CD-ROM drive but cannot find IDE controller, which is required in this version of VirtualBox"));
-
- // this is for rollback later
- MyHardDiskAttachment mhda;
- mhda.pMachine = pNewMachine;
-
- convertDiskAttachmentValues(*pController,
- 2, // interpreted as secondary master
- mhda.controllerType, // Bstr
- mhda.lControllerPort,
- mhda.lDevice);
-
- Log(("Attaching CD-ROM to port %d on device %d\n", mhda.lControllerPort, mhda.lDevice));
-
- rc = sMachine->AttachDevice(mhda.controllerType.raw(),
- mhda.lControllerPort,
- mhda.lDevice,
- DeviceType_DVD,
- NULL);
- if (FAILED(rc)) throw rc;
-
- stack.llHardDiskAttachments.push_back(mhda);
- } // end for (itHD = avsdeHDs.begin();
-
rc = sMachine->SaveSettings();
if (FAILED(rc)) throw rc;
@@ -2373,12 +2962,17 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis,
if (FAILED(rc)) throw rc;
stack.fSessionOpen = false;
}
- catch(HRESULT /* aRC */)
+ catch(HRESULT aRC)
{
+ com::ErrorInfo info;
+
if (stack.fSessionOpen)
stack.pSession->UnlockMachine();
- throw;
+ if (info.isFullAvailable())
+ throw setError(aRC, Utf8Str(info.getText()).c_str());
+ else
+ throw setError(aRC, "Unknown error during OVF import");
}
}
@@ -2390,37 +2984,190 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis,
// we need another try/catch block.
try
{
+#ifdef LOG_ENABLED
+ if (LogIsEnabled())
+ {
+ size_t i = 0;
+ for (list<VirtualSystemDescriptionEntry*>::const_iterator itHD = avsdeHDs.begin(); itHD != avsdeHDs.end(); ++itHD, i++)
+ Log(("avsdeHDs[%zu]: strRef=%s\n", i, (*itHD)->strRef.c_str()));
+ }
+#endif
+
// to attach things we need to open a session for the new machine
rc = pNewMachine->LockMachine(stack.pSession, LockType_Write);
if (FAILED(rc)) throw rc;
stack.fSessionOpen = true;
- /* Iterate over all given disk images */
- list<VirtualSystemDescriptionEntry*>::const_iterator itHD;
- for (itHD = avsdeHDs.begin();
- itHD != avsdeHDs.end();
- ++itHD)
+ /* get VM name from virtual system description. Only one record is possible (size of list is equal 1). */
+ std::list<VirtualSystemDescriptionEntry*> vmName = vsdescThis->findByType(VirtualSystemDescriptionType_Name);
+ std::list<VirtualSystemDescriptionEntry*>::iterator vmNameIt = vmName.begin();
+ VirtualSystemDescriptionEntry* vmNameEntry = *vmNameIt;
+
+ ovf::DiskImagesMap::const_iterator oit = stack.mapDisks.begin();
+ std::set<RTCString> disksResolvedNames;
+
+ uint32_t cImportedDisks = 0;
+
+ while(oit != stack.mapDisks.end() && cImportedDisks != avsdeHDs.size())
{
- VirtualSystemDescriptionEntry *vsdeHD = *itHD;
+ ovf::DiskImage diCurrent = oit->second;
+ ovf::VirtualDisksMap::const_iterator itVDisk = vsysThis.mapVirtualDisks.begin();
+
+ VirtualSystemDescriptionEntry *vsdeTargetHD = 0;
+ Log(("diCurrent.strDiskId=%s\n", diCurrent.strDiskId.c_str()));
+
+ /*
+ *
+ * Iterate over all given disk images of the virtual system
+ * disks description. We need to find the target disk path,
+ * which could be changed by the user.
+ *
+ */
+ {
+ list<VirtualSystemDescriptionEntry*>::const_iterator itHD;
+ for (itHD = avsdeHDs.begin();
+ itHD != avsdeHDs.end();
+ ++itHD)
+ {
+ VirtualSystemDescriptionEntry *vsdeHD = *itHD;
+ if (vsdeHD->strRef == diCurrent.strDiskId)
+ {
+ vsdeTargetHD = vsdeHD;
+ break;
+ }
+ }
+ if (!vsdeTargetHD)
+ {
+ /* possible case if a disk image belongs to other virtual system (OVF package with multiple VMs inside) */
+ LogWarning(("OVA/OVF import: Disk image %s was missed during import of VM %s\n",
+ oit->first.c_str(), vmNameEntry->strOvf.c_str()));
+ ++oit;
+ continue;
+ }
+
+ //diCurrent.strDiskId contains the disk identifier (e.g. "vmdisk1"), which should exist
+ //in the virtual system's disks map under that ID and also in the global images map
+ itVDisk = vsysThis.mapVirtualDisks.find(diCurrent.strDiskId);
+ if (itVDisk == vsysThis.mapVirtualDisks.end())
+ throw setError(E_FAIL,
+ tr("Internal inconsistency looking up disk image '%s'"),
+ diCurrent.strHref.c_str());
+ }
+
+ /*
+ * preliminary check availability of the image
+ * This step is useful if image is placed in the OVA (TAR) package
+ */
+
+ Utf8Str name = applianceIOName(applianceIOTar);
+
+ if (strncmp(pStorage->pVDImageIfaces->pszInterfaceName, name.c_str(), name.length()) == 0)
+ {
+ /* It means that we possibly have imported the storage earlier on the previous loop steps*/
+ std::set<RTCString>::const_iterator h = disksResolvedNames.find(diCurrent.strHref);
+ if (h != disksResolvedNames.end())
+ {
+ /* Yes, disk name was found, we can skip it*/
+ ++oit;
+ continue;
+ }
+
+ RTCString availableImage(diCurrent.strHref);
+
+ rc = preCheckImageAvailability(pStorage,
+ availableImage
+ );
+
+ if (SUCCEEDED(rc))
+ {
+ /* current opened file isn't the same as passed one */
+ if(availableImage.compare(diCurrent.strHref, Utf8Str::CaseInsensitive) != 0)
+ {
+ /*
+ * availableImage contains the disk file reference (e.g. "disk1.vmdk"), which should exist
+ * in the global images map.
+ * And find the disk from the OVF's disk list
+ *
+ */
+ {
+ ovf::DiskImagesMap::const_iterator itDiskImage = stack.mapDisks.begin();
+ while (++itDiskImage != stack.mapDisks.end())
+ {
+ if (itDiskImage->second.strHref.compare(availableImage, Utf8Str::CaseInsensitive) == 0)
+ break;
+ }
+ if (itDiskImage == stack.mapDisks.end())
+ throw setError(E_FAIL,
+ tr("Internal inconsistency looking up disk image '%s'. "
+ "Check compliance OVA package structure and file names "
+ "references in the section <References> in the OVF file"),
+ availableImage.c_str());
+
+ /* replace with a new found disk image */
+ diCurrent = *(&itDiskImage->second);
+ }
+
+ /*
+ * Again iterate over all given disk images of the virtual system
+ * disks description using the found disk image
+ */
+ {
+ list<VirtualSystemDescriptionEntry*>::const_iterator itHD;
+ for (itHD = avsdeHDs.begin();
+ itHD != avsdeHDs.end();
+ ++itHD)
+ {
+ VirtualSystemDescriptionEntry *vsdeHD = *itHD;
+ if (vsdeHD->strRef == diCurrent.strDiskId)
+ {
+ vsdeTargetHD = vsdeHD;
+ break;
+ }
+ }
+ if (!vsdeTargetHD)
+ /*
+ * in this case it's an error because something wrong with OVF description file.
+ * May be VBox imports OVA package with wrong file sequence inside the archive.
+ */
+ throw setError(E_FAIL,
+ tr("Internal inconsistency looking up disk image '%s'"),
+ diCurrent.strHref.c_str());
+
+ itVDisk = vsysThis.mapVirtualDisks.find(diCurrent.strDiskId);
+ if (itVDisk == vsysThis.mapVirtualDisks.end())
+ throw setError(E_FAIL,
+ tr("Internal inconsistency looking up disk image '%s'"),
+ diCurrent.strHref.c_str());
+ }
+ }
+ else
+ {
+ ++oit;
+ }
+ }
+ else
+ {
+ ++oit;
+ continue;
+ }
+ }
+ else
+ {
+ /* just continue with normal files*/
+ ++oit;
+ }
- // vsdeHD->strRef contains the disk identifier (e.g. "vmdisk1"), which should exist
- // in the virtual system's disks map under that ID and also in the global images map
- ovf::VirtualDisksMap::const_iterator itVirtualDisk = vsysThis.mapVirtualDisks.find(vsdeHD->strRef);
- // and find the disk from the OVF's disk list
- ovf::DiskImagesMap::const_iterator itDiskImage = stack.mapDisks.find(vsdeHD->strRef);
- if ( (itVirtualDisk == vsysThis.mapVirtualDisks.end())
- || (itDiskImage == stack.mapDisks.end())
- )
- throw setError(E_FAIL,
- tr("Internal inconsistency looking up disk image '%s'"),
- vsdeHD->strRef.c_str());
-
- const ovf::DiskImage &ovfDiskImage = itDiskImage->second;
- const ovf::VirtualDisk &ovfVdisk = itVirtualDisk->second;
+ const ovf::VirtualDisk &ovfVdisk = itVDisk->second;
+
+ /* very important to store disk name for the next checks */
+ disksResolvedNames.insert(diCurrent.strHref);
ComObjPtr<Medium> pTargetHD;
- importOneDiskImage(ovfDiskImage,
- vsdeHD->strVboxCurrent,
+
+ Utf8Str savedVBoxCurrent = vsdeTargetHD->strVBoxCurrent;
+
+ importOneDiskImage(diCurrent,
+ &vsdeTargetHD->strVBoxCurrent,
pTargetHD,
stack,
pCallbacks,
@@ -2429,7 +3176,8 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis,
// now use the new uuid to attach the disk image to our new machine
ComPtr<IMachine> sMachine;
rc = stack.pSession->COMGETTER(Machine)(sMachine.asOutParam());
- if (FAILED(rc)) throw rc;
+ if (FAILED(rc))
+ throw rc;
// find the hard disk controller to which we should attach
ovf::HardDiskController hdc = (*vsysThis.mapControllers.find(ovfVdisk.idController)).second;
@@ -2444,34 +3192,88 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis,
mhda.lControllerPort,
mhda.lDevice);
- Log(("Attaching disk %s to port %d on device %d\n", vsdeHD->strVboxCurrent.c_str(), mhda.lControllerPort, mhda.lDevice));
+ Log(("Attaching disk %s to port %d on device %d\n",
+ vsdeTargetHD->strVBoxCurrent.c_str(), mhda.lControllerPort, mhda.lDevice));
- rc = sMachine->AttachDevice(mhda.controllerType.raw(), // wstring name
- mhda.lControllerPort, // long controllerPort
- mhda.lDevice, // long device
- DeviceType_HardDisk, // DeviceType_T type
- pTargetHD);
- if (FAILED(rc)) throw rc;
+ Utf8Str vdf = typeOfVirtualDiskFormatFromURI(diCurrent.strFormat);
+
+ if (vdf.compare("RAW", Utf8Str::CaseInsensitive) == 0)
+ {
+ ComPtr<IMedium> dvdImage(pTargetHD);
+
+ rc = mVirtualBox->OpenMedium(Bstr(vsdeTargetHD->strVBoxCurrent).raw(),
+ DeviceType_DVD,
+ AccessMode_ReadWrite,
+ false,
+ dvdImage.asOutParam());
+
+ if (FAILED(rc))
+ throw rc;
+
+ rc = sMachine->AttachDevice(mhda.controllerType.raw(),// wstring name
+ mhda.lControllerPort, // long controllerPort
+ mhda.lDevice, // long device
+ DeviceType_DVD, // DeviceType_T type
+ dvdImage);
+ if (FAILED(rc))
+ throw rc;
+ }
+ else
+ {
+ rc = sMachine->AttachDevice(mhda.controllerType.raw(),// wstring name
+ mhda.lControllerPort, // long controllerPort
+ mhda.lDevice, // long device
+ DeviceType_HardDisk, // DeviceType_T type
+ pTargetHD);
+
+ if (FAILED(rc))
+ throw rc;
+ }
stack.llHardDiskAttachments.push_back(mhda);
rc = sMachine->SaveSettings();
- if (FAILED(rc)) throw rc;
- } // end for (itHD = avsdeHDs.begin();
+ if (FAILED(rc))
+ throw rc;
+
+ /* restore */
+ vsdeTargetHD->strVBoxCurrent = savedVBoxCurrent;
+
+ ++cImportedDisks;
+
+ } // end while(oit != stack.mapDisks.end())
+
+ /*
+ * quantity of the imported disks isn't equal to the size of the avsdeHDs list.
+ */
+ if(cImportedDisks < avsdeHDs.size())
+ {
+ LogWarning(("Not all disk images were imported for VM %s. Check OVF description file.",
+ vmNameEntry->strOvf.c_str()));
+ }
// only now that we're done with all disks, close the session
rc = stack.pSession->UnlockMachine();
- if (FAILED(rc)) throw rc;
+
+ if (FAILED(rc))
+ throw rc;
+
stack.fSessionOpen = false;
}
- catch(HRESULT /* aRC */)
+ catch(HRESULT aRC)
{
+ com::ErrorInfo info;
+
if (stack.fSessionOpen)
stack.pSession->UnlockMachine();
- throw;
+ if (info.isFullAvailable())
+ throw setError(aRC, Utf8Str(info.getText()).c_str());
+ else
+ throw setError(aRC, "Unknown error during OVF import");
}
}
+ LogFlowFuncLeave();
}
/**
@@ -2509,6 +3311,7 @@ void Appliance::importVBoxMachine(ComObjPtr<VirtualSystemDescription> &vsdescThi
PVDINTERFACEIO pCallbacks,
PSHASTORAGE pStorage)
{
+ LogFlowFuncEnter();
Assert(vsdescThis->m->pConfig);
HRESULT rc = S_OK;
@@ -2516,10 +3319,8 @@ void Appliance::importVBoxMachine(ComObjPtr<VirtualSystemDescription> &vsdescThi
settings::MachineConfigFile &config = *vsdescThis->m->pConfig;
/*
- *
* step 1): modify machine config according to OVF config, in case the user
* has modified them using setFinalValues()
- *
*/
/* OS Type */
@@ -2544,7 +3345,34 @@ void Appliance::importVBoxMachine(ComObjPtr<VirtualSystemDescription> &vsdescThi
#ifdef VBOX_WITH_USB
/* USB controller */
- config.hardwareMachine.usbController.fEnabled = stack.fUSBEnabled;
+ if (stack.fUSBEnabled)
+ {
+ /** @todo r=klaus add support for arbitrary USB controller types, this can't handle multiple controllers due to its design anyway */
+
+ /* usually the OHCI controller is enabled already, need to check */
+ bool fOHCIEnabled = false;
+ settings::USBControllerList &llUSBControllers = config.hardwareMachine.usbSettings.llUSBControllers;
+ settings::USBControllerList::iterator it;
+ for (it = llUSBControllers.begin(); it != llUSBControllers.end(); ++it)
+ {
+ if (it->enmType == USBControllerType_OHCI)
+ {
+ fOHCIEnabled = true;
+ break;
+ }
+ }
+
+ if (!fOHCIEnabled)
+ {
+ settings::USBController ctrl;
+ ctrl.strName = "OHCI";
+ ctrl.enmType = USBControllerType_OHCI;
+
+ llUSBControllers.push_back(ctrl);
+ }
+ }
+ else
+ config.hardwareMachine.usbSettings.llUSBControllers.clear();
#endif
/* Audio adapter */
if (stack.strAudioAdapter.isNotEmpty())
@@ -2558,13 +3386,14 @@ void Appliance::importVBoxMachine(ComObjPtr<VirtualSystemDescription> &vsdescThi
settings::NetworkAdaptersList &llNetworkAdapters = config.hardwareMachine.llNetworkAdapters;
/* First disable all network cards, they will be enabled below again. */
settings::NetworkAdaptersList::iterator it1;
- bool fKeepAllMACs = m->optList.contains(ImportOptions_KeepAllMACs);
- bool fKeepNATMACs = m->optList.contains(ImportOptions_KeepNATMACs);
+ bool fKeepAllMACs = m->optListImport.contains(ImportOptions_KeepAllMACs);
+ bool fKeepNATMACs = m->optListImport.contains(ImportOptions_KeepNATMACs);
for (it1 = llNetworkAdapters.begin(); it1 != llNetworkAdapters.end(); ++it1)
{
it1->fEnabled = false;
if (!( fKeepAllMACs
- || (fKeepNATMACs && it1->mode == NetworkAttachmentType_NAT)))
+ || (fKeepNATMACs && it1->mode == NetworkAttachmentType_NAT)
+ || (fKeepNATMACs && it1->mode == NetworkAttachmentType_NATNetwork)))
Host::generateMACAddress(it1->strMACAddress);
}
/* Now iterate over all network entries. */
@@ -2593,7 +3422,7 @@ void Appliance::importVBoxMachine(ComObjPtr<VirtualSystemDescription> &vsdescThi
if (it1->ulSlot == iSlot)
{
it1->fEnabled = true;
- it1->type = (NetworkAdapterType_T)vsdeNW->strVboxCurrent.toUInt32();
+ it1->type = (NetworkAdapterType_T)vsdeNW->strVBoxCurrent.toUInt32();
break;
}
}
@@ -2612,7 +3441,7 @@ void Appliance::importVBoxMachine(ComObjPtr<VirtualSystemDescription> &vsdescThi
* failures. A long fixed bug, however the OVF files are long lived. */
settings::StorageControllersList &llControllers = config.storageMachine.llStorageControllers;
Guid hdUuid;
- uint32_t cHardDisks = 0;
+ uint32_t cDisks = 0;
bool fInconsistent = false;
bool fRepairDuplicate = false;
settings::StorageControllersList::iterator it3;
@@ -2636,17 +3465,17 @@ void Appliance::importVBoxMachine(ComObjPtr<VirtualSystemDescription> &vsdescThi
else if (it4->deviceType == DeviceType_HardDisk)
{
const Guid &thisUuid = it4->uuid;
- cHardDisks++;
- if (cHardDisks == 1)
+ cDisks++;
+ if (cDisks == 1)
{
- if (hdUuid.isEmpty())
+ if (hdUuid.isZero())
hdUuid = thisUuid;
else
fInconsistent = true;
}
else
{
- if (thisUuid.isEmpty())
+ if (thisUuid.isZero())
fInconsistent = true;
else if (thisUuid == hdUuid)
fRepairDuplicate = true;
@@ -2656,141 +3485,290 @@ void Appliance::importVBoxMachine(ComObjPtr<VirtualSystemDescription> &vsdescThi
}
}
/* paranoia... */
- if (fInconsistent || cHardDisks == 1)
+ if (fInconsistent || cDisks == 1)
fRepairDuplicate = false;
/*
- *
* step 2: scan the machine config for media attachments
- *
*/
+ /* get VM name from virtual system description. Only one record is possible (size of list is equal 1). */
+ std::list<VirtualSystemDescriptionEntry*> vmName = vsdescThis->findByType(VirtualSystemDescriptionType_Name);
+ std::list<VirtualSystemDescriptionEntry*>::iterator vmNameIt = vmName.begin();
+ VirtualSystemDescriptionEntry* vmNameEntry = *vmNameIt;
+
/* Get all hard disk descriptions. */
std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
std::list<VirtualSystemDescriptionEntry*>::iterator avsdeHDsIt = avsdeHDs.begin();
/* paranoia - if there is no 1:1 match do not try to repair. */
- if (cHardDisks != avsdeHDs.size())
+ if (cDisks != avsdeHDs.size())
fRepairDuplicate = false;
- // for each storage controller...
- for (settings::StorageControllersList::iterator sit = config.storageMachine.llStorageControllers.begin();
- sit != config.storageMachine.llStorageControllers.end();
- ++sit)
- {
- settings::StorageController &sc = *sit;
+ // there must be an image in the OVF disk structs with the same UUID
- // find the OVF virtual system description entry for this storage controller
- switch (sc.storageBus)
- {
- case StorageBus_SATA:
- break;
- case StorageBus_SCSI:
- break;
- case StorageBus_IDE:
- break;
- case StorageBus_SAS:
- break;
- }
+ ovf::DiskImagesMap::const_iterator oit = stack.mapDisks.begin();
+ std::set<RTCString> disksResolvedNames;
- // for each medium attachment to this controller...
- for (settings::AttachedDevicesList::iterator dit = sc.llAttachedDevices.begin();
- dit != sc.llAttachedDevices.end();
- ++dit)
- {
- settings::AttachedDevice &d = *dit;
+ uint32_t cImportedDisks = 0;
- if (d.uuid.isEmpty())
- // empty DVD and floppy media
- continue;
+ while(oit != stack.mapDisks.end() && cImportedDisks != avsdeHDs.size())
+ {
+ ovf::DiskImage diCurrent = oit->second;
- // When repairing a broken VirtualBox xml config section (written
- // by VirtualBox versions earlier than 3.2.10) assume the disks
- // show up in the same order as in the OVF description.
- if (fRepairDuplicate)
+ VirtualSystemDescriptionEntry *vsdeTargetHD = 0;
+
+ {
+ /* Iterate over all given disk images of the virtual system
+ * disks description. We need to find the target disk path,
+ * which could be changed by the user. */
+ list<VirtualSystemDescriptionEntry*>::const_iterator itHD;
+ for (itHD = avsdeHDs.begin();
+ itHD != avsdeHDs.end();
+ ++itHD)
{
- VirtualSystemDescriptionEntry *vsdeHD = *avsdeHDsIt;
- ovf::DiskImagesMap::const_iterator itDiskImage = stack.mapDisks.find(vsdeHD->strRef);
- if (itDiskImage != stack.mapDisks.end())
+ VirtualSystemDescriptionEntry *vsdeHD = *itHD;
+ if (vsdeHD->strRef == oit->first)
{
- const ovf::DiskImage &di = itDiskImage->second;
- d.uuid = Guid(di.uuidVbox);
+ vsdeTargetHD = vsdeHD;
+ break;
}
- ++avsdeHDsIt;
}
- // convert the Guid to string
- Utf8Str strUuid = d.uuid.toString();
+ if (!vsdeTargetHD)
+ {
+ /* possible case if a disk image belongs to other virtual system (OVF package with multiple VMs inside) */
+ LogWarning(("OVA/OVF import: Disk image %s was missed during import of VM %s\n",
+ oit->first.c_str(), vmNameEntry->strOvf.c_str()));
+ ++oit;
+ continue;
+ }
+ }
+
+ /*
+ * preliminary check availability of the image
+ * This step is useful if image is placed in the OVA (TAR) package
+ */
- // there must be an image in the OVF disk structs with the same UUID
- bool fFound = false;
- for (ovf::DiskImagesMap::const_iterator oit = stack.mapDisks.begin();
- oit != stack.mapDisks.end();
- ++oit)
+ Utf8Str name = applianceIOName(applianceIOTar);
+
+ if (strncmp(pStorage->pVDImageIfaces->pszInterfaceName, name.c_str(), name.length()) == 0)
+ {
+ /* It means that we possibly have imported the storage earlier on the previous loop steps*/
+ std::set<RTCString>::const_iterator h = disksResolvedNames.find(diCurrent.strHref);
+ if (h != disksResolvedNames.end())
{
- const ovf::DiskImage &di = oit->second;
+ /* Yes, disk name was found, we can skip it*/
+ ++oit;
+ continue;
+ }
+
+ RTCString availableImage(diCurrent.strHref);
- if (di.uuidVbox == strUuid)
+ rc = preCheckImageAvailability(pStorage,
+ availableImage
+ );
+
+ if (SUCCEEDED(rc))
+ {
+ /* current opened file isn't the same as passed one */
+ if(availableImage.compare(diCurrent.strHref, Utf8Str::CaseInsensitive) != 0)
{
- VirtualSystemDescriptionEntry *vsdeTargetHD = 0;
+ // availableImage contains the disk identifier (e.g. "vmdisk1"), which should exist
+ // in the virtual system's disks map under that ID and also in the global images map
+ // and find the disk from the OVF's disk list
+ ovf::DiskImagesMap::const_iterator itDiskImage = stack.mapDisks.begin();
+ while (++itDiskImage != stack.mapDisks.end())
+ {
+ if(itDiskImage->second.strHref.compare(availableImage, Utf8Str::CaseInsensitive) == 0 )
+ break;
+ }
+ if (itDiskImage == stack.mapDisks.end())
+ {
+ throw setError(E_FAIL,
+ tr("Internal inconsistency looking up disk image '%s'. "
+ "Check compliance OVA package structure and file names "
+ "references in the section <References> in the OVF file."),
+ availableImage.c_str());
+ }
- /* Iterate over all given disk images of the virtual system
- * disks description. We need to find the target disk path,
- * which could be changed by the user. */
+ /* replace with a new found disk image */
+ diCurrent = *(&itDiskImage->second);
+
+ /*
+ * Again iterate over all given disk images of the virtual system
+ * disks description using the found disk image
+ */
list<VirtualSystemDescriptionEntry*>::const_iterator itHD;
for (itHD = avsdeHDs.begin();
itHD != avsdeHDs.end();
++itHD)
{
VirtualSystemDescriptionEntry *vsdeHD = *itHD;
- if (vsdeHD->strRef == oit->first)
+ if (vsdeHD->strRef == diCurrent.strDiskId)
{
vsdeTargetHD = vsdeHD;
break;
}
}
if (!vsdeTargetHD)
+ /*
+ * in this case it's an error because something wrong with OVF description file.
+ * May be VBox imports OVA package with wrong file sequence inside the archive.
+ */
throw setError(E_FAIL,
tr("Internal inconsistency looking up disk image '%s'"),
- oit->first.c_str());
+ diCurrent.strHref.c_str());
+ }
+ else
+ {
+ ++oit;
+ }
+ }
+ else
+ {
+ ++oit;
+ continue;
+ }
+ }
+ else
+ {
+ /* just continue with normal files*/
+ ++oit;
+ }
- /*
- *
- * step 3: import disk
- *
- */
- ComObjPtr<Medium> pTargetHD;
- importOneDiskImage(di,
- vsdeTargetHD->strVboxCurrent,
- pTargetHD,
- stack,
- pCallbacks,
- pStorage);
+ /* Important! to store disk name for the next checks */
+ disksResolvedNames.insert(diCurrent.strHref);
+
+ // there must be an image in the OVF disk structs with the same UUID
+ bool fFound = false;
+ Utf8Str strUuid;
+
+ // for each storage controller...
+ for (settings::StorageControllersList::iterator sit = config.storageMachine.llStorageControllers.begin();
+ sit != config.storageMachine.llStorageControllers.end();
+ ++sit)
+ {
+ settings::StorageController &sc = *sit;
+
+ // find the OVF virtual system description entry for this storage controller
+ switch (sc.storageBus)
+ {
+ case StorageBus_SATA:
+ break;
+ case StorageBus_SCSI:
+ break;
+ case StorageBus_IDE:
+ break;
+ case StorageBus_SAS:
+ break;
+ }
+
+ // for each medium attachment to this controller...
+ for (settings::AttachedDevicesList::iterator dit = sc.llAttachedDevices.begin();
+ dit != sc.llAttachedDevices.end();
+ ++dit)
+ {
+ settings::AttachedDevice &d = *dit;
+
+ if (d.uuid.isZero())
+ // empty DVD and floppy media
+ continue;
+
+ // When repairing a broken VirtualBox xml config section (written
+ // by VirtualBox versions earlier than 3.2.10) assume the disks
+ // show up in the same order as in the OVF description.
+ if (fRepairDuplicate)
+ {
+ VirtualSystemDescriptionEntry *vsdeHD = *avsdeHDsIt;
+ ovf::DiskImagesMap::const_iterator itDiskImage = stack.mapDisks.find(vsdeHD->strRef);
+ if (itDiskImage != stack.mapDisks.end())
+ {
+ const ovf::DiskImage &di = itDiskImage->second;
+ d.uuid = Guid(di.uuidVBox);
+ }
+ ++avsdeHDsIt;
+ }
+
+ // convert the Guid to string
+ strUuid = d.uuid.toString();
+
+ if (diCurrent.uuidVBox != strUuid)
+ {
+ continue;
+ }
+
+ /*
+ * step 3: import disk
+ */
+ Utf8Str savedVBoxCurrent = vsdeTargetHD->strVBoxCurrent;
+ ComObjPtr<Medium> pTargetHD;
+ importOneDiskImage(diCurrent,
+ &vsdeTargetHD->strVBoxCurrent,
+ pTargetHD,
+ stack,
+ pCallbacks,
+ pStorage);
+
+ Bstr hdId;
+
+ Utf8Str vdf = typeOfVirtualDiskFormatFromURI(diCurrent.strFormat);
+
+ if (vdf.compare("RAW", Utf8Str::CaseInsensitive) == 0)
+ {
+ ComPtr<IMedium> dvdImage(pTargetHD);
+
+ rc = mVirtualBox->OpenMedium(Bstr(vsdeTargetHD->strVBoxCurrent).raw(),
+ DeviceType_DVD,
+ AccessMode_ReadWrite,
+ false,
+ dvdImage.asOutParam());
+
+ if (FAILED(rc)) throw rc;
// ... and replace the old UUID in the machine config with the one of
// the imported disk that was just created
- Bstr hdId;
+ rc = dvdImage->COMGETTER(Id)(hdId.asOutParam());
+ if (FAILED(rc)) throw rc;
+ }
+ else
+ {
+ // ... and replace the old UUID in the machine config with the one of
+ // the imported disk that was just created
rc = pTargetHD->COMGETTER(Id)(hdId.asOutParam());
if (FAILED(rc)) throw rc;
+ }
- d.uuid = hdId;
+ /* restore */
+ vsdeTargetHD->strVBoxCurrent = savedVBoxCurrent;
- fFound = true;
- break;
- }
- }
+ d.uuid = hdId;
+ fFound = true;
+ break;
+ } // for (settings::AttachedDevicesList::const_iterator dit = sc.llAttachedDevices.begin();
+ } // for (settings::StorageControllersList::const_iterator sit = config.storageMachine.llStorageControllers.begin();
// no disk with such a UUID found:
- if (!fFound)
- throw setError(E_FAIL,
- tr("<vbox:Machine> element in OVF contains a medium attachment for the disk image %s but the OVF describes no such image"),
- strUuid.c_str());
- } // for (settings::AttachedDevicesList::const_iterator dit = sc.llAttachedDevices.begin();
- } // for (settings::StorageControllersList::const_iterator sit = config.storageMachine.llStorageControllers.begin();
+ if (!fFound)
+ throw setError(E_FAIL,
+ tr("<vbox:Machine> element in OVF contains a medium attachment for the disk image %s "
+ "but the OVF describes no such image"),
+ strUuid.c_str());
+
+ ++cImportedDisks;
+
+ }// while(oit != stack.mapDisks.end())
+
+ /*
+ * quantity of the imported disks isn't equal to the size of the avsdeHDs list.
+ */
+ if(cImportedDisks < avsdeHDs.size())
+ {
+ LogWarning(("Not all disk images were imported for VM %s. Check OVF description file.",
+ vmNameEntry->strOvf.c_str()));
+ }
/*
- *
* step 4): create the machine and have it import the config
- *
*/
ComObjPtr<Machine> pNewMachine;
@@ -2800,8 +3778,8 @@ void Appliance::importVBoxMachine(ComObjPtr<VirtualSystemDescription> &vsdescThi
// this magic constructor fills the new machine object with the MachineConfig
// instance that we created from the vbox:Machine
rc = pNewMachine->init(mVirtualBox,
- stack.strNameVBox, // name from OVF preparations; can be suffixed to avoid duplicates, or changed by user
- config); // the whole machine config
+ stack.strNameVBox,// name from OVF preparations; can be suffixed to avoid duplicates
+ config); // the whole machine config
if (FAILED(rc)) throw rc;
pReturnNewMachine = ComPtr<IMachine>(pNewMachine);
@@ -2815,6 +3793,8 @@ void Appliance::importVBoxMachine(ComObjPtr<VirtualSystemDescription> &vsdescThi
rc = pNewMachine->COMGETTER(Id)(bstrNewMachineId.asOutParam());
if (FAILED(rc)) throw rc;
m->llGuidsMachinesCreated.push_back(Guid(bstrNewMachineId));
+
+ LogFlowFuncLeave();
}
void Appliance::importMachines(ImportStack &stack,
@@ -2824,9 +3804,14 @@ void Appliance::importMachines(ImportStack &stack,
HRESULT rc = S_OK;
// this is safe to access because this thread only gets started
- // if pReader != NULL
const ovf::OVFReader &reader = *m->pReader;
+ /*
+ * get the SHA digest version that was set in accordance with the value of attribute "xmlns:ovf"
+ * of the element <Envelope> in the OVF file during reading operation. See readFSImpl().
+ */
+ pStorage->fSha256 = m->fSha256;
+
// create a session for the machine + disks we manipulate below
rc = stack.pSession.createInprocObject(CLSID_Session);
if (FAILED(rc)) throw rc;
@@ -2837,7 +3822,8 @@ void Appliance::importMachines(ImportStack &stack,
size_t i = 0;
for (it = reader.m_llVirtualSystems.begin(),
it1 = m->virtualSystemDescriptions.begin();
- it != reader.m_llVirtualSystems.end();
+ it != reader.m_llVirtualSystems.end(),
+ it1 != m->virtualSystemDescriptions.end();
++it, ++it1, ++i)
{
const ovf::VirtualSystem &vsysThis = *it;
@@ -2860,7 +3846,7 @@ void Appliance::importMachines(ImportStack &stack,
if (vsdeName.size() < 1)
throw setError(VBOX_E_FILE_ERROR,
tr("Missing VM name"));
- stack.strNameVBox = vsdeName.front()->strVboxCurrent;
+ stack.strNameVBox = vsdeName.front()->strVBoxCurrent;
// have VirtualBox suggest where the filename would be placed so we can
// put the disk images in the same directory
@@ -2874,6 +3860,7 @@ void Appliance::importMachines(ImportStack &stack,
// and determine the machine folder from that
stack.strMachineFolder = bstrMachineFilename;
stack.strMachineFolder.stripFilename();
+ LogFunc(("i=%zu strName=%s bstrMachineFilename=%ls\n", i, stack.strNameVBox.c_str(), bstrMachineFilename.raw()));
// guest OS type
std::list<VirtualSystemDescriptionEntry*> vsdeOS;
@@ -2881,14 +3868,14 @@ void Appliance::importMachines(ImportStack &stack,
if (vsdeOS.size() < 1)
throw setError(VBOX_E_FILE_ERROR,
tr("Missing guest OS type"));
- stack.strOsTypeVBox = vsdeOS.front()->strVboxCurrent;
+ stack.strOsTypeVBox = vsdeOS.front()->strVBoxCurrent;
// CPU count
std::list<VirtualSystemDescriptionEntry*> vsdeCPU = vsdescThis->findByType(VirtualSystemDescriptionType_CPU);
if (vsdeCPU.size() != 1)
throw setError(VBOX_E_FILE_ERROR, tr("CPU count missing"));
- stack.cCPUs = vsdeCPU.front()->strVboxCurrent.toUInt32();
+ stack.cCPUs = vsdeCPU.front()->strVBoxCurrent.toUInt32();
// We need HWVirt & IO-APIC if more than one CPU is requested
if (stack.cCPUs > 1)
{
@@ -2900,7 +3887,7 @@ void Appliance::importMachines(ImportStack &stack,
std::list<VirtualSystemDescriptionEntry*> vsdeRAM = vsdescThis->findByType(VirtualSystemDescriptionType_Memory);
if (vsdeRAM.size() != 1)
throw setError(VBOX_E_FILE_ERROR, tr("RAM size missing"));
- stack.ulMemorySizeMB = (ULONG)vsdeRAM.front()->strVboxCurrent.toUInt64();
+ stack.ulMemorySizeMB = (ULONG)vsdeRAM.front()->strVBoxCurrent.toUInt64();
#ifdef VBOX_WITH_USB
// USB controller
@@ -2913,12 +3900,12 @@ void Appliance::importMachines(ImportStack &stack,
std::list<VirtualSystemDescriptionEntry*> vsdeAudioAdapter = vsdescThis->findByType(VirtualSystemDescriptionType_SoundCard);
/* @todo: we support one audio adapter only */
if (vsdeAudioAdapter.size() > 0)
- stack.strAudioAdapter = vsdeAudioAdapter.front()->strVboxCurrent;
+ stack.strAudioAdapter = vsdeAudioAdapter.front()->strVBoxCurrent;
// for the description of the new machine, always use the OVF entry, the user may have changed it in the import config
std::list<VirtualSystemDescriptionEntry*> vsdeDescription = vsdescThis->findByType(VirtualSystemDescriptionType_Description);
if (vsdeDescription.size())
- stack.strDescription = vsdeDescription.front()->strVboxCurrent;
+ stack.strDescription = vsdeDescription.front()->strVBoxCurrent;
// import vbox:machine or OVF now
if (vsdescThis->m->pConfig)
diff --git a/src/VBox/Main/src-server/AudioAdapterImpl.cpp b/src/VBox/Main/src-server/AudioAdapterImpl.cpp
index 9b6dbf17..089359b2 100644
--- a/src/VBox/Main/src-server/AudioAdapterImpl.cpp
+++ b/src/VBox/Main/src-server/AudioAdapterImpl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Main/src-server/BIOSSettingsImpl.cpp b/src/VBox/Main/src-server/BIOSSettingsImpl.cpp
index bc40820b..1cc0a5e2 100644
--- a/src/VBox/Main/src-server/BIOSSettingsImpl.cpp
+++ b/src/VBox/Main/src-server/BIOSSettingsImpl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -507,6 +507,23 @@ STDMETHODIMP BIOSSettings::COMSETTER(TimeOffset)(LONG64 offset)
return S_OK;
}
+STDMETHODIMP BIOSSettings::COMGETTER(NonVolatileStorageFile)(BSTR *pbstrPath)
+{
+ CheckComArgOutPointerValid(pbstrPath);
+
+ AutoCaller autoCaller(this);
+ HRESULT hrc = autoCaller.rc();
+ if (SUCCEEDED(hrc))
+ {
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+ Bstr bstrEmpty("");
+ hrc = bstrEmpty.cloneToEx(pbstrPath);
+ }
+
+ return hrc;
+}
+
+
// IBIOSSettings methods
/////////////////////////////////////////////////////////////////////////////
diff --git a/src/VBox/Main/src-server/BandwidthControlImpl.cpp b/src/VBox/Main/src-server/BandwidthControlImpl.cpp
index 70e2d243..5235bb6b 100644
--- a/src/VBox/Main/src-server/BandwidthControlImpl.cpp
+++ b/src/VBox/Main/src-server/BandwidthControlImpl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-2014 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -25,6 +25,8 @@
#include "Logging.h"
#include <iprt/cpp/utils.h>
+#include <VBox/com/array.h>
+#include <algorithm>
// defines
/////////////////////////////////////////////////////////////////////////////
@@ -72,8 +74,6 @@ void BandwidthControl::FinalRelease()
*
* @returns COM result indicator.
* @param aParent Pointer to our parent object.
- * @param aName Name of the storage controller.
- * @param aInstance Instance number of the storage controller.
*/
HRESULT BandwidthControl::init(Machine *aParent)
{
@@ -147,7 +147,7 @@ HRESULT BandwidthControl::init(Machine *aParent,
}
/**
- * Initializes the storage controller object given another guest object
+ * Initializes the bandwidth control object given another guest object
* (a kind of copy constructor). This object makes a private copy of data
* of the original object passed as an argument.
*/
@@ -176,7 +176,7 @@ HRESULT BandwidthControl::initCopy(Machine *aParent, BandwidthControl *aThat)
{
ComObjPtr<BandwidthGroup> group;
group.createObject();
- group->init(this, *it);
+ group->initCopy(this, *it);
m->llBandwidthGroups->push_back(group);
++ it;
}
@@ -215,7 +215,7 @@ void BandwidthControl::copyFrom (BandwidthControl *aThat)
AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
- /* create private copies of all filters */
+ /* create private copies of all bandwidth groups */
m->llBandwidthGroups.backup();
m->llBandwidthGroups->clear();
for (BandwidthGroupList::const_iterator it = aThat->m->llBandwidthGroups->begin();
@@ -285,7 +285,7 @@ void BandwidthControl::commit()
{
AutoWriteLock peerlock(m->pPeer COMMA_LOCKVAL_SRC_POS);
- /* Commit all changes to new controllers (this will reshare data with
+ /* Commit all changes to new groups (this will reshare data with
* peers for those who have peers) */
BandwidthGroupList *newList = new BandwidthGroupList();
BandwidthGroupList::const_iterator it = m->llBandwidthGroups->begin();
@@ -313,7 +313,7 @@ void BandwidthControl::commit()
++it;
}
- /* uninit old peer's controllers that are left */
+ /* uninit old peer's groups that are left */
it = m->pPeer->m->llBandwidthGroups->begin();
while (it != m->pPeer->m->llBandwidthGroups->end())
{
@@ -321,7 +321,7 @@ void BandwidthControl::commit()
++it;
}
- /* attach new list of controllers to our peer */
+ /* attach new list of groups to our peer */
m->pPeer->m->llBandwidthGroups.attach(newList);
}
else
@@ -334,7 +334,7 @@ void BandwidthControl::commit()
else
{
/* the list of groups itself is not changed,
- * just commit changes to controllers themselves */
+ * just commit changes to groups themselves */
commitBandwidthGroups = true;
}
@@ -379,10 +379,10 @@ void BandwidthControl::uninit()
}
/**
- * Returns a storage controller object with the given name.
+ * Returns a bandwidth group object with the given name.
*
- * @param aName storage controller name to find
- * @param aStorageController where to return the found storage controller
+ * @param aName bandwidth group name to find
+ * @param aBandwidthGroup where to return the found bandwidth group
* @param aSetError true to set extended error info on failure
*/
HRESULT BandwidthControl::getBandwidthGroupByName(const Utf8Str &aName,
diff --git a/src/VBox/Main/src-server/BandwidthGroupImpl.cpp b/src/VBox/Main/src-server/BandwidthGroupImpl.cpp
index aef8f4c1..22ba0c1b 100644
--- a/src/VBox/Main/src-server/BandwidthGroupImpl.cpp
+++ b/src/VBox/Main/src-server/BandwidthGroupImpl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-2014 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -80,8 +80,9 @@ void BandwidthGroup::FinalRelease()
*
* @returns COM result indicator.
* @param aParent Pointer to our parent object.
- * @param aName Name of the storage controller.
- * @param aInstance Instance number of the storage controller.
+ * @param aName Name of the bandwidth group.
+ * @param aType Type of the bandwidth group (net, disk).
+ * @param aMaxBytesPerSec Maximum bandwidth for the bandwidth group.
*/
HRESULT BandwidthGroup::init(BandwidthControl *aParent,
const Utf8Str &aName,
@@ -175,7 +176,7 @@ HRESULT BandwidthGroup::init(BandwidthControl *aParent,
}
/**
- * Initializes the storage controller object given another guest object
+ * Initializes the bandwidth group object given another guest object
* (a kind of copy constructor). This object makes a private copy of data
* of the original object passed as an argument.
*/
diff --git a/src/VBox/Main/src-server/ClientToken.cpp b/src/VBox/Main/src-server/ClientToken.cpp
new file mode 100644
index 00000000..be0afb8a
--- /dev/null
+++ b/src/VBox/Main/src-server/ClientToken.cpp
@@ -0,0 +1,262 @@
+/** @file
+ *
+ * VirtualBox API client session crash token handling
+ */
+
+/*
+ * Copyright (C) 2004-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/log.h>
+#include <iprt/semaphore.h>
+#include <iprt/process.h>
+
+#ifdef VBOX_WITH_SYS_V_IPC_SESSION_WATCHER
+# include <errno.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <sys/ipc.h>
+# include <sys/sem.h>
+#endif
+
+#include <VBox/com/defs.h>
+
+#include <vector>
+
+#include "VirtualBoxBase.h"
+#include "AutoCaller.h"
+#include "ClientToken.h"
+#include "MachineImpl.h"
+
+Machine::ClientToken::ClientToken()
+{
+ AssertReleaseFailed();
+}
+
+Machine::ClientToken::~ClientToken()
+{
+#if defined(RT_OS_WINDOWS)
+ if (mClientToken)
+ ::CloseHandle(mClientToken);
+#elif defined(RT_OS_OS2)
+ if (mClientToken != NULLHANDLE)
+ ::DosCloseMutexSem(mClientToken);
+#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
+ if (mClientToken >= 0)
+ ::semctl(mClientToken, 0, IPC_RMID);
+# ifdef VBOX_WITH_NEW_SYS_V_KEYGEN
+ mClientTokenId = "0";
+# endif /* VBOX_WITH_NEW_SYS_V_KEYGEN */
+#elif defined(VBOX_WITH_GENERIC_SESSION_WATCHER)
+ /* release the token, uses reference counting */
+ if (mClientToken)
+ {
+ if (!mClientTokenPassed)
+ mClientToken->Release();
+ mClientToken = NULL;
+ }
+#else
+# error "Port me!"
+#endif
+ mClientToken = CTTOKENARG;
+}
+
+Machine::ClientToken::ClientToken(const ComObjPtr<Machine> &pMachine,
+ SessionMachine *pSessionMachine) :
+ mMachine(pMachine)
+{
+#if defined(RT_OS_WINDOWS)
+ NOREF(pSessionMachine);
+ Bstr tokenId = pMachine->mData->m_strConfigFileFull;
+ for (size_t i = 0; i < tokenId.length(); i++)
+ if (tokenId.raw()[i] == '\\')
+ tokenId.raw()[i] = '/';
+ mClientToken = ::CreateMutex(NULL, FALSE, tokenId.raw());
+ mClientTokenId = tokenId;
+ AssertMsg(mClientToken,
+ ("Cannot create token '%s', err=%d",
+ mClientTokenId.c_str(), ::GetLastError()));
+#elif defined(RT_OS_OS2)
+ NOREF(pSessionMachine);
+ Utf8Str ipcSem = Utf8StrFmt("\\SEM32\\VBOX\\VM\\{%RTuuid}",
+ pMachine->mData->mUuid.raw());
+ mClientTokenId = ipcSem;
+ APIRET arc = ::DosCreateMutexSem((PSZ)ipcSem.c_str(), &mClientToken, 0, FALSE);
+ AssertMsg(arc == NO_ERROR,
+ ("Cannot create token '%s', arc=%ld",
+ ipcSem.c_str(), arc));
+#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
+ NOREF(pSessionMachine);
+# ifdef VBOX_WITH_NEW_SYS_V_KEYGEN
+# if defined(RT_OS_FREEBSD) && (HC_ARCH_BITS == 64)
+ /** @todo Check that this still works correctly. */
+ AssertCompileSize(key_t, 8);
+# else
+ AssertCompileSize(key_t, 4);
+# endif
+ key_t key;
+ mClientToken = -1;
+ mClientTokenId = "0";
+ for (uint32_t i = 0; i < 1 << 24; i++)
+ {
+ key = ((uint32_t)'V' << 24) | i;
+ int sem = ::semget(key, 1, S_IRUSR | S_IWUSR | IPC_CREAT | IPC_EXCL);
+ if (sem >= 0 || (errno != EEXIST && errno != EACCES))
+ {
+ mClientToken = sem;
+ if (sem >= 0)
+ mClientTokenId = BstrFmt("%u", key);
+ break;
+ }
+ }
+# else /* !VBOX_WITH_NEW_SYS_V_KEYGEN */
+ Utf8Str semName = pMachine->mData->m_strConfigFileFull;
+ char *pszSemName = NULL;
+ RTStrUtf8ToCurrentCP(&pszSemName, semName);
+ key_t key = ::ftok(pszSemName, 'V');
+ RTStrFree(pszSemName);
+
+ mClientToken = ::semget(key, 1, S_IRWXU | S_IRWXG | S_IRWXO | IPC_CREAT);
+# endif /* !VBOX_WITH_NEW_SYS_V_KEYGEN */
+
+ int errnoSave = errno;
+ if (mClientToken < 0 && errnoSave == ENOSYS)
+ {
+ mMachine->setError(E_FAIL,
+ tr("Cannot create IPC semaphore. Most likely your host kernel lacks "
+ "support for SysV IPC. Check the host kernel configuration for "
+ "CONFIG_SYSVIPC=y"));
+ mClientToken = CTTOKENARG;
+ return;
+ }
+ /* ENOSPC can also be the result of VBoxSVC crashes without properly freeing
+ * the token */
+ if (mClientToken < 0 && errnoSave == ENOSPC)
+ {
+#ifdef RT_OS_LINUX
+ mMachine->setError(E_FAIL,
+ tr("Cannot create IPC semaphore because the system limit for the "
+ "maximum number of semaphore sets (SEMMNI), or the system wide "
+ "maximum number of semaphores (SEMMNS) would be exceeded. The "
+ "current set of SysV IPC semaphores can be determined from "
+ "the file /proc/sysvipc/sem"));
+#else
+ mMachine->setError(E_FAIL,
+ tr("Cannot create IPC semaphore because the system-imposed limit "
+ "on the maximum number of allowed semaphores or semaphore "
+ "identifiers system-wide would be exceeded"));
+#endif
+ mClientToken = CTTOKENARG;
+ return;
+ }
+ AssertMsgReturnVoid(mClientToken >= 0, ("Cannot create token, errno=%d", errnoSave));
+ /* set the initial value to 1 */
+ int rv = ::semctl(mClientToken, 0, SETVAL, 1);
+ errnoSave = errno;
+ if (rv != 0)
+ {
+ ::semctl(mClientToken, 0, IPC_RMID);
+ mClientToken = CTTOKENARG;
+ AssertMsgFailedReturnVoid(("Cannot init token, errno=%d", errnoSave));
+ }
+#elif defined(VBOX_WITH_GENERIC_SESSION_WATCHER)
+ ComObjPtr<MachineToken> pToken;
+ HRESULT rc = pToken.createObject();
+ if (SUCCEEDED(rc))
+ {
+ rc = pToken->init(pSessionMachine);
+ if (SUCCEEDED(rc))
+ {
+ mClientToken = pToken;
+ if (mClientToken)
+ {
+ rc = mClientToken->AddRef();
+ if (FAILED(rc))
+ mClientToken = NULL;
+ }
+ }
+ }
+ pToken.setNull();
+ mClientTokenPassed = false;
+ /* mClientTokenId isn't really used */
+ mClientTokenId = pMachine->mData->m_strConfigFileFull;
+ AssertMsg(mClientToken,
+ ("Cannot create token '%s', rc=%Rhrc",
+ mClientTokenId.c_str(), rc));
+#else
+# error "Port me!"
+#endif
+}
+
+bool Machine::ClientToken::isReady()
+{
+ return mClientToken != CTTOKENARG;
+}
+
+void Machine::ClientToken::getId(Utf8Str &strId)
+{
+ strId = mClientTokenId;
+}
+
+CTTOKENTYPE Machine::ClientToken::getToken()
+{
+#ifdef VBOX_WITH_GENERIC_SESSION_WATCHER
+ mClientTokenPassed = true;
+#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */
+ return mClientToken;
+}
+
+#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER
+bool Machine::ClientToken::release()
+{
+ bool terminated = false;
+
+#if defined(RT_OS_WINDOWS)
+ AssertMsg(mClientToken, ("semaphore must be created"));
+
+ /* release the token */
+ ::ReleaseMutex(mClientToken);
+ terminated = true;
+#elif defined(RT_OS_OS2)
+ AssertMsg(mClientToken, ("semaphore must be created"));
+
+ /* release the token */
+ ::DosReleaseMutexSem(mClientToken);
+ terminated = true;
+#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
+ AssertMsg(mClientToken >= 0, ("semaphore must be created"));
+ int val = ::semctl(mClientToken, 0, GETVAL);
+ if (val > 0)
+ {
+ /* the semaphore is signaled, meaning the session is terminated */
+ terminated = true;
+ }
+#elif defined(VBOX_WITH_GENERIC_SESSION_WATCHER)
+ /** @todo r=klaus never tested, this code is not reached */
+ AssertMsg(mClientToken, ("token must be created"));
+ /* release the token, uses reference counting */
+ if (mClientToken)
+ {
+ if (!mClientTokenPassed)
+ mClientToken->Release();
+ mClientToken = NULL;
+ }
+ terminated = true;
+#else
+# error "Port me!"
+#endif
+ return terminated;
+}
+#endif /* !VBOX_WITH_GENERIC_SESSION_WATCHER */
+
+/* vi: set tabstop=4 shiftwidth=4 expandtab: */
diff --git a/src/VBox/Main/src-server/ClientWatcher.cpp b/src/VBox/Main/src-server/ClientWatcher.cpp
new file mode 100644
index 00000000..6d2cd3f1
--- /dev/null
+++ b/src/VBox/Main/src-server/ClientWatcher.cpp
@@ -0,0 +1,849 @@
+/** @file
+ *
+ * VirtualBox API client session crash watcher
+ */
+
+/*
+ * Copyright (C) 2006-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/log.h>
+#include <iprt/semaphore.h>
+#include <iprt/process.h>
+
+#include <VBox/com/defs.h>
+
+#include <vector>
+
+#include "VirtualBoxBase.h"
+#include "AutoCaller.h"
+#include "ClientWatcher.h"
+#include "ClientToken.h"
+#include "VirtualBoxImpl.h"
+#include "MachineImpl.h"
+
+#if defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) || defined(VBOX_WITH_GENERIC_SESSION_WATCHER)
+/** Table for adaptive timeouts. After an update the counter starts at the
+ * maximum value and decreases to 0, i.e. first the short timeouts are used
+ * and then the longer ones. This minimizes the detection latency in the
+ * cases where a change is expected, for crashes. */
+static const RTMSINTERVAL s_aUpdateTimeoutSteps[] = { 500, 200, 100, 50, 20, 10, 5 };
+#endif
+
+
+
+VirtualBox::ClientWatcher::ClientWatcher() :
+ mLock(LOCKCLASS_OBJECTSTATE)
+{
+ AssertReleaseFailed();
+}
+
+VirtualBox::ClientWatcher::~ClientWatcher()
+{
+ if (mThread != NIL_RTTHREAD)
+ {
+ /* signal the client watcher thread, should be exiting now */
+ update();
+ /* wait for termination */
+ RTThreadWait(mThread, RT_INDEFINITE_WAIT, NULL);
+ mThread = NIL_RTTHREAD;
+ }
+ mProcesses.clear();
+#if defined(RT_OS_WINDOWS)
+ if (mUpdateReq != NULL)
+ {
+ ::CloseHandle(mUpdateReq);
+ mUpdateReq = NULL;
+ }
+#elif defined(RT_OS_OS2) || defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) || defined(VBOX_WITH_GENERIC_SESSION_WATCHER)
+ if (mUpdateReq != NIL_RTSEMEVENT)
+ {
+ RTSemEventDestroy(mUpdateReq);
+ mUpdateReq = NIL_RTSEMEVENT;
+ }
+#else
+# error "Port me!"
+#endif
+}
+
+VirtualBox::ClientWatcher::ClientWatcher(const ComObjPtr<VirtualBox> &pVirtualBox) :
+ mVirtualBox(pVirtualBox),
+ mThread(NIL_RTTHREAD),
+ mUpdateReq(CWUPDATEREQARG),
+ mLock(LOCKCLASS_OBJECTSTATE)
+{
+#if defined(RT_OS_WINDOWS)
+ mUpdateReq = ::CreateEvent(NULL, FALSE, FALSE, NULL);
+#elif defined(RT_OS_OS2)
+ RTSemEventCreate(&mUpdateReq);
+#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) || defined(VBOX_WITH_GENERIC_SESSION_WATCHER)
+ RTSemEventCreate(&mUpdateReq);
+ /* start with high timeouts, nothing to do */
+ ASMAtomicUoWriteU8(&mUpdateAdaptCtr, 0);
+#else
+# error "Port me!"
+#endif
+
+ int vrc = RTThreadCreate(&mThread,
+ worker,
+ (void *)this,
+ 0,
+ RTTHREADTYPE_MAIN_WORKER,
+ RTTHREADFLAGS_WAITABLE,
+ "Watcher");
+ AssertRC(vrc);
+}
+
+bool VirtualBox::ClientWatcher::isReady()
+{
+ return mThread != NIL_RTTHREAD;
+}
+
+/**
+ * Sends a signal to the thread to rescan the clients/VMs having open sessions.
+ */
+void VirtualBox::ClientWatcher::update()
+{
+ AssertReturnVoid(mThread != NIL_RTTHREAD);
+
+ /* sent an update request */
+#if defined(RT_OS_WINDOWS)
+ ::SetEvent(mUpdateReq);
+#elif defined(RT_OS_OS2)
+ RTSemEventSignal(mUpdateReq);
+#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
+ /* use short timeouts, as we expect changes */
+ ASMAtomicUoWriteU8(&mUpdateAdaptCtr, RT_ELEMENTS(s_aUpdateTimeoutSteps) - 1);
+ RTSemEventSignal(mUpdateReq);
+#elif defined(VBOX_WITH_GENERIC_SESSION_WATCHER)
+ RTSemEventSignal(mUpdateReq);
+#else
+# error "Port me!"
+#endif
+}
+
+/**
+ * Adds a process to the list of processes to be reaped. This call should be
+ * followed by a call to update() to cause the necessary actions immediately,
+ * in case the process crashes straight away.
+ */
+void VirtualBox::ClientWatcher::addProcess(RTPROCESS pid)
+{
+ AssertReturnVoid(mThread != NIL_RTTHREAD);
+ /* @todo r=klaus, do the reaping on all platforms! */
+#ifndef RT_OS_WINDOWS
+ AutoWriteLock alock(mLock COMMA_LOCKVAL_SRC_POS);
+ mProcesses.push_back(pid);
+#endif
+}
+
+/**
+ * Thread worker function that watches the termination of all client processes
+ * that have open sessions using IMachine::LockMachine()
+ */
+/*static*/
+DECLCALLBACK(int) VirtualBox::ClientWatcher::worker(RTTHREAD /* thread */, void *pvUser)
+{
+ LogFlowFuncEnter();
+
+ VirtualBox::ClientWatcher *that = (VirtualBox::ClientWatcher *)pvUser;
+ Assert(that);
+
+ typedef std::vector<ComObjPtr<Machine> > MachineVector;
+ typedef std::vector<ComObjPtr<SessionMachine> > SessionMachineVector;
+
+ SessionMachineVector machines;
+ MachineVector spawnedMachines;
+
+ size_t cnt = 0;
+ size_t cntSpawned = 0;
+
+ VirtualBoxBase::initializeComForThread();
+
+#if defined(RT_OS_WINDOWS)
+
+ /// @todo (dmik) processes reaping!
+
+ HANDLE handles[MAXIMUM_WAIT_OBJECTS];
+ handles[0] = that->mUpdateReq;
+
+ do
+ {
+ AutoCaller autoCaller(that->mVirtualBox);
+ /* VirtualBox has been early uninitialized, terminate */
+ if (!autoCaller.isOk())
+ break;
+
+ do
+ {
+ /* release the caller to let uninit() ever proceed */
+ autoCaller.release();
+
+ DWORD rc = ::WaitForMultipleObjects((DWORD)(1 + cnt + cntSpawned),
+ handles,
+ FALSE,
+ INFINITE);
+
+ /* Restore the caller before using VirtualBox. If it fails, this
+ * means VirtualBox is being uninitialized and we must terminate. */
+ autoCaller.add();
+ if (!autoCaller.isOk())
+ break;
+
+ bool update = false;
+
+ if (rc == WAIT_OBJECT_0)
+ {
+ /* update event is signaled */
+ update = true;
+ }
+ else if (rc > WAIT_OBJECT_0 && rc <= (WAIT_OBJECT_0 + cnt))
+ {
+ /* machine mutex is released */
+ (machines[rc - WAIT_OBJECT_0 - 1])->checkForDeath();
+ update = true;
+ }
+ else if (rc > WAIT_ABANDONED_0 && rc <= (WAIT_ABANDONED_0 + cnt))
+ {
+ /* machine mutex is abandoned due to client process termination */
+ (machines[rc - WAIT_ABANDONED_0 - 1])->checkForDeath();
+ update = true;
+ }
+ else if (rc > WAIT_OBJECT_0 + cnt && rc <= (WAIT_OBJECT_0 + cntSpawned))
+ {
+ /* spawned VM process has terminated (normally or abnormally) */
+ (spawnedMachines[rc - WAIT_OBJECT_0 - cnt - 1])->
+ checkForSpawnFailure();
+ update = true;
+ }
+
+ if (update)
+ {
+ /* close old process handles */
+ for (size_t i = 1 + cnt; i < 1 + cnt + cntSpawned; ++i)
+ CloseHandle(handles[i]);
+
+ // get reference to the machines list in VirtualBox
+ VirtualBox::MachinesOList &allMachines = that->mVirtualBox->getMachinesList();
+
+ // lock the machines list for reading
+ AutoReadLock thatLock(allMachines.getLockHandle() COMMA_LOCKVAL_SRC_POS);
+
+ /* obtain a new set of opened machines */
+ cnt = 0;
+ machines.clear();
+
+ for (MachinesOList::iterator it = allMachines.begin();
+ it != allMachines.end();
+ ++it)
+ {
+ /// @todo handle situations with more than 64 objects
+ AssertMsgBreak((1 + cnt) <= MAXIMUM_WAIT_OBJECTS,
+ ("MAXIMUM_WAIT_OBJECTS reached"));
+
+ ComObjPtr<SessionMachine> sm;
+ if ((*it)->isSessionOpenOrClosing(sm))
+ {
+ AutoCaller smCaller(sm);
+ if (smCaller.isOk())
+ {
+ AutoReadLock smLock(sm COMMA_LOCKVAL_SRC_POS);
+ Machine::ClientToken *ct = sm->getClientToken();
+ if (ct)
+ {
+ HANDLE ipcSem = ct->getToken();
+ machines.push_back(sm);
+ handles[1 + cnt] = ipcSem;
+ ++cnt;
+ }
+ }
+ }
+ }
+
+ LogFlowFunc(("UPDATE: direct session count = %d\n", cnt));
+
+ /* obtain a new set of spawned machines */
+ cntSpawned = 0;
+ spawnedMachines.clear();
+
+ for (MachinesOList::iterator it = allMachines.begin();
+ it != allMachines.end();
+ ++it)
+ {
+ /// @todo handle situations with more than 64 objects
+ AssertMsgBreak((1 + cnt + cntSpawned) <= MAXIMUM_WAIT_OBJECTS,
+ ("MAXIMUM_WAIT_OBJECTS reached"));
+
+ if ((*it)->isSessionSpawning())
+ {
+ ULONG pid;
+ HRESULT hrc = (*it)->COMGETTER(SessionPID)(&pid);
+ if (SUCCEEDED(hrc))
+ {
+ HANDLE ph = OpenProcess(SYNCHRONIZE, FALSE, pid);
+ AssertMsg(ph != NULL, ("OpenProcess (pid=%d) failed with %d\n",
+ pid, GetLastError()));
+ if (ph != NULL)
+ {
+ spawnedMachines.push_back(*it);
+ handles[1 + cnt + cntSpawned] = ph;
+ ++cntSpawned;
+ }
+ }
+ }
+ }
+
+ LogFlowFunc(("UPDATE: spawned session count = %d\n", cntSpawned));
+
+ // machines lock unwinds here
+ }
+ }
+ while (true);
+ }
+ while (0);
+
+ /* close old process handles */
+ for (size_t i = 1 + cnt; i < 1 + cnt + cntSpawned; ++i)
+ CloseHandle(handles[i]);
+
+ /* release sets of machines if any */
+ machines.clear();
+ spawnedMachines.clear();
+
+ ::CoUninitialize();
+
+#elif defined(RT_OS_OS2)
+
+ /// @todo (dmik) processes reaping!
+
+ /* according to PMREF, 64 is the maximum for the muxwait list */
+ SEMRECORD handles[64];
+
+ HMUX muxSem = NULLHANDLE;
+
+ do
+ {
+ AutoCaller autoCaller(that->mVirtualBox);
+ /* VirtualBox has been early uninitialized, terminate */
+ if (!autoCaller.isOk())
+ break;
+
+ do
+ {
+ /* release the caller to let uninit() ever proceed */
+ autoCaller.release();
+
+ int vrc = RTSemEventWait(that->mUpdateReq, 500);
+
+ /* Restore the caller before using VirtualBox. If it fails, this
+ * means VirtualBox is being uninitialized and we must terminate. */
+ autoCaller.add();
+ if (!autoCaller.isOk())
+ break;
+
+ bool update = false;
+ bool updateSpawned = false;
+
+ if (RT_SUCCESS(vrc))
+ {
+ /* update event is signaled */
+ update = true;
+ updateSpawned = true;
+ }
+ else
+ {
+ AssertMsg(vrc == VERR_TIMEOUT || vrc == VERR_INTERRUPTED,
+ ("RTSemEventWait returned %Rrc\n", vrc));
+
+ /* are there any mutexes? */
+ if (cnt > 0)
+ {
+ /* figure out what's going on with machines */
+
+ unsigned long semId = 0;
+ APIRET arc = ::DosWaitMuxWaitSem(muxSem,
+ SEM_IMMEDIATE_RETURN, &semId);
+
+ if (arc == NO_ERROR)
+ {
+ /* machine mutex is normally released */
+ Assert(semId >= 0 && semId < cnt);
+ if (semId >= 0 && semId < cnt)
+ {
+#if 0//def DEBUG
+ {
+ AutoReadLock machineLock(machines[semId] COMMA_LOCKVAL_SRC_POS);
+ LogFlowFunc(("released mutex: machine='%ls'\n",
+ machines[semId]->name().raw()));
+ }
+#endif
+ machines[semId]->checkForDeath();
+ }
+ update = true;
+ }
+ else if (arc == ERROR_SEM_OWNER_DIED)
+ {
+ /* machine mutex is abandoned due to client process
+ * termination; find which mutex is in the Owner Died
+ * state */
+ for (size_t i = 0; i < cnt; ++i)
+ {
+ PID pid; TID tid;
+ unsigned long reqCnt;
+ arc = DosQueryMutexSem((HMTX)handles[i].hsemCur, &pid, &tid, &reqCnt);
+ if (arc == ERROR_SEM_OWNER_DIED)
+ {
+ /* close the dead mutex as asked by PMREF */
+ ::DosCloseMutexSem((HMTX)handles[i].hsemCur);
+
+ Assert(i >= 0 && i < cnt);
+ if (i >= 0 && i < cnt)
+ {
+#if 0//def DEBUG
+ {
+ AutoReadLock machineLock(machines[semId] COMMA_LOCKVAL_SRC_POS);
+ LogFlowFunc(("mutex owner dead: machine='%ls'\n",
+ machines[i]->name().raw()));
+ }
+#endif
+ machines[i]->checkForDeath();
+ }
+ }
+ }
+ update = true;
+ }
+ else
+ AssertMsg(arc == ERROR_INTERRUPT || arc == ERROR_TIMEOUT,
+ ("DosWaitMuxWaitSem returned %d\n", arc));
+ }
+
+ /* are there any spawning sessions? */
+ if (cntSpawned > 0)
+ {
+ for (size_t i = 0; i < cntSpawned; ++i)
+ updateSpawned |= (spawnedMachines[i])->
+ checkForSpawnFailure();
+ }
+ }
+
+ if (update || updateSpawned)
+ {
+ // get reference to the machines list in VirtualBox
+ VirtualBox::MachinesOList &allMachines = that->mVirtualBox->getMachinesList();
+
+ // lock the machines list for reading
+ AutoReadLock thatLock(allMachines.getLockHandle() COMMA_LOCKVAL_SRC_POS);
+
+ if (update)
+ {
+ /* close the old muxsem */
+ if (muxSem != NULLHANDLE)
+ ::DosCloseMuxWaitSem(muxSem);
+
+ /* obtain a new set of opened machines */
+ cnt = 0;
+ machines.clear();
+
+ for (MachinesOList::iterator it = allMachines.begin();
+ it != allMachines.end(); ++it)
+ {
+ /// @todo handle situations with more than 64 objects
+ AssertMsg(cnt <= 64 /* according to PMREF */,
+ ("maximum of 64 mutex semaphores reached (%d)",
+ cnt));
+
+ ComObjPtr<SessionMachine> sm;
+ if ((*it)->isSessionOpenOrClosing(sm))
+ {
+ AutoCaller smCaller(sm);
+ if (smCaller.isOk())
+ {
+ AutoReadLock smLock(sm COMMA_LOCKVAL_SRC_POS);
+ ClientToken *ct = sm->getClientToken();
+ if (ct)
+ {
+ HMTX ipcSem = ct->getToken();
+ machines.push_back(sm);
+ handles[cnt].hsemCur = (HSEM)ipcSem;
+ handles[cnt].ulUser = cnt;
+ ++cnt;
+ }
+ }
+ }
+ }
+
+ LogFlowFunc(("UPDATE: direct session count = %d\n", cnt));
+
+ if (cnt > 0)
+ {
+ /* create a new muxsem */
+ APIRET arc = ::DosCreateMuxWaitSem(NULL, &muxSem, cnt,
+ handles,
+ DCMW_WAIT_ANY);
+ AssertMsg(arc == NO_ERROR,
+ ("DosCreateMuxWaitSem returned %d\n", arc));
+ NOREF(arc);
+ }
+ }
+
+ if (updateSpawned)
+ {
+ /* obtain a new set of spawned machines */
+ spawnedMachines.clear();
+
+ for (MachinesOList::iterator it = allMachines.begin();
+ it != allMachines.end(); ++it)
+ {
+ if ((*it)->isSessionSpawning())
+ spawnedMachines.push_back(*it);
+ }
+
+ cntSpawned = spawnedMachines.size();
+ LogFlowFunc(("UPDATE: spawned session count = %d\n", cntSpawned));
+ }
+ }
+ }
+ while (true);
+ }
+ while (0);
+
+ /* close the muxsem */
+ if (muxSem != NULLHANDLE)
+ ::DosCloseMuxWaitSem(muxSem);
+
+ /* release sets of machines if any */
+ machines.clear();
+ spawnedMachines.clear();
+
+#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
+
+ bool update = false;
+ bool updateSpawned = false;
+
+ do
+ {
+ AutoCaller autoCaller(that->mVirtualBox);
+ if (!autoCaller.isOk())
+ break;
+
+ do
+ {
+ /* release the caller to let uninit() ever proceed */
+ autoCaller.release();
+
+ /* determine wait timeout adaptively: after updating information
+ * relevant to the client watcher, check a few times more
+ * frequently. This ensures good reaction time when the signalling
+ * has to be done a bit before the actual change for technical
+ * reasons, and saves CPU cycles when no activities are expected. */
+ RTMSINTERVAL cMillies;
+ {
+ uint8_t uOld, uNew;
+ do
+ {
+ uOld = ASMAtomicUoReadU8(&that->mUpdateAdaptCtr);
+ uNew = uOld ? uOld - 1 : uOld;
+ } while (!ASMAtomicCmpXchgU8(&that->mUpdateAdaptCtr, uNew, uOld));
+ Assert(uOld <= RT_ELEMENTS(s_aUpdateTimeoutSteps) - 1);
+ cMillies = s_aUpdateTimeoutSteps[uOld];
+ }
+
+ int rc = RTSemEventWait(that->mUpdateReq, cMillies);
+
+ /*
+ * Restore the caller before using VirtualBox. If it fails, this
+ * means VirtualBox is being uninitialized and we must terminate.
+ */
+ autoCaller.add();
+ if (!autoCaller.isOk())
+ break;
+
+ if (RT_SUCCESS(rc) || update || updateSpawned)
+ {
+ /* RT_SUCCESS(rc) means an update event is signaled */
+
+ // get reference to the machines list in VirtualBox
+ VirtualBox::MachinesOList &allMachines = that->mVirtualBox->getMachinesList();
+
+ // lock the machines list for reading
+ AutoReadLock thatLock(allMachines.getLockHandle() COMMA_LOCKVAL_SRC_POS);
+
+ if (RT_SUCCESS(rc) || update)
+ {
+ /* obtain a new set of opened machines */
+ machines.clear();
+
+ for (MachinesOList::iterator it = allMachines.begin();
+ it != allMachines.end();
+ ++it)
+ {
+ ComObjPtr<SessionMachine> sm;
+ if ((*it)->isSessionOpenOrClosing(sm))
+ machines.push_back(sm);
+ }
+
+ cnt = machines.size();
+ LogFlowFunc(("UPDATE: direct session count = %d\n", cnt));
+ }
+
+ if (RT_SUCCESS(rc) || updateSpawned)
+ {
+ /* obtain a new set of spawned machines */
+ spawnedMachines.clear();
+
+ for (MachinesOList::iterator it = allMachines.begin();
+ it != allMachines.end();
+ ++it)
+ {
+ if ((*it)->isSessionSpawning())
+ spawnedMachines.push_back(*it);
+ }
+
+ cntSpawned = spawnedMachines.size();
+ LogFlowFunc(("UPDATE: spawned session count = %d\n", cntSpawned));
+ }
+
+ // machines lock unwinds here
+ }
+
+ update = false;
+ for (size_t i = 0; i < cnt; ++i)
+ update |= (machines[i])->checkForDeath();
+
+ updateSpawned = false;
+ for (size_t i = 0; i < cntSpawned; ++i)
+ updateSpawned |= (spawnedMachines[i])->checkForSpawnFailure();
+
+ /* reap child processes */
+ {
+ AutoWriteLock alock(that->mLock COMMA_LOCKVAL_SRC_POS);
+ if (that->mProcesses.size())
+ {
+ LogFlowFunc(("UPDATE: child process count = %d\n",
+ that->mProcesses.size()));
+ VirtualBox::ClientWatcher::ProcessList::iterator it = that->mProcesses.begin();
+ while (it != that->mProcesses.end())
+ {
+ RTPROCESS pid = *it;
+ RTPROCSTATUS status;
+ int vrc = ::RTProcWait(pid, RTPROCWAIT_FLAGS_NOBLOCK, &status);
+ if (vrc == VINF_SUCCESS)
+ {
+ if ( status.enmReason != RTPROCEXITREASON_NORMAL
+ || status.iStatus != RTEXITCODE_SUCCESS)
+ {
+ switch (status.enmReason)
+ {
+ default:
+ case RTPROCEXITREASON_NORMAL:
+ LogRel(("Reaper: Pid %d (%x) exited normally: %d (%#x)\n",
+ pid, pid, status.iStatus, status.iStatus));
+ break;
+ case RTPROCEXITREASON_ABEND:
+ LogRel(("Reaper: Pid %d (%x) abended: %d (%#x)\n",
+ pid, pid, status.iStatus, status.iStatus));
+ break;
+ case RTPROCEXITREASON_SIGNAL:
+ LogRel(("Reaper: Pid %d (%x) was signalled: %d (%#x)\n",
+ pid, pid, status.iStatus, status.iStatus));
+ break;
+ }
+ }
+ else
+ LogFlowFunc(("pid %d (%x) was reaped, status=%d, reason=%d\n",
+ pid, pid, status.iStatus,
+ status.enmReason));
+ it = that->mProcesses.erase(it);
+ }
+ else
+ {
+ LogFlowFunc(("pid %d (%x) was NOT reaped, vrc=%Rrc\n",
+ pid, pid, vrc));
+ if (vrc != VERR_PROCESS_RUNNING)
+ {
+ /* remove the process if it is not already running */
+ it = that->mProcesses.erase(it);
+ }
+ else
+ ++it;
+ }
+ }
+ }
+ }
+ }
+ while (true);
+ }
+ while (0);
+
+ /* release sets of machines if any */
+ machines.clear();
+ spawnedMachines.clear();
+
+#elif defined(VBOX_WITH_GENERIC_SESSION_WATCHER)
+
+ bool updateSpawned = false;
+
+ do
+ {
+ AutoCaller autoCaller(that->mVirtualBox);
+ if (!autoCaller.isOk())
+ break;
+
+ do
+ {
+ /* release the caller to let uninit() ever proceed */
+ autoCaller.release();
+
+ /* determine wait timeout adaptively: after updating information
+ * relevant to the client watcher, check a few times more
+ * frequently. This ensures good reaction time when the signalling
+ * has to be done a bit before the actual change for technical
+ * reasons, and saves CPU cycles when no activities are expected. */
+ RTMSINTERVAL cMillies;
+ {
+ uint8_t uOld, uNew;
+ do
+ {
+ uOld = ASMAtomicUoReadU8(&that->mUpdateAdaptCtr);
+ uNew = uOld ? uOld - 1 : uOld;
+ } while (!ASMAtomicCmpXchgU8(&that->mUpdateAdaptCtr, uNew, uOld));
+ Assert(uOld <= RT_ELEMENTS(s_aUpdateTimeoutSteps) - 1);
+ cMillies = s_aUpdateTimeoutSteps[uOld];
+ }
+
+ int rc = RTSemEventWait(that->mUpdateReq, cMillies);
+
+ /*
+ * Restore the caller before using VirtualBox. If it fails, this
+ * means VirtualBox is being uninitialized and we must terminate.
+ */
+ autoCaller.add();
+ if (!autoCaller.isOk())
+ break;
+
+ /** @todo this quite big effort for catching machines in spawning
+ * state which can't be caught by the token mechanism (as the token
+ * can't be in the other process yet) could be eliminated if the
+ * reaping is made smarter, having cross-reference information
+ * from the pid to the corresponding machine object. Both cases do
+ * more or less the same thing anyway. */
+ if (RT_SUCCESS(rc) || updateSpawned)
+ {
+ /* RT_SUCCESS(rc) means an update event is signaled */
+
+ // get reference to the machines list in VirtualBox
+ VirtualBox::MachinesOList &allMachines = that->mVirtualBox->getMachinesList();
+
+ // lock the machines list for reading
+ AutoReadLock thatLock(allMachines.getLockHandle() COMMA_LOCKVAL_SRC_POS);
+
+ if (RT_SUCCESS(rc) || updateSpawned)
+ {
+ /* obtain a new set of spawned machines */
+ spawnedMachines.clear();
+
+ for (MachinesOList::iterator it = allMachines.begin();
+ it != allMachines.end();
+ ++it)
+ {
+ if ((*it)->isSessionSpawning())
+ spawnedMachines.push_back(*it);
+ }
+
+ cntSpawned = spawnedMachines.size();
+ LogFlowFunc(("UPDATE: spawned session count = %d\n", cntSpawned));
+ }
+
+ NOREF(cnt);
+ // machines lock unwinds here
+ }
+
+ updateSpawned = false;
+ for (size_t i = 0; i < cntSpawned; ++i)
+ updateSpawned |= (spawnedMachines[i])->checkForSpawnFailure();
+
+ /* reap child processes */
+ {
+ AutoWriteLock alock(that->mLock COMMA_LOCKVAL_SRC_POS);
+ if (that->mProcesses.size())
+ {
+ LogFlowFunc(("UPDATE: child process count = %d\n",
+ that->mProcesses.size()));
+ VirtualBox::ClientWatcher::ProcessList::iterator it = that->mProcesses.begin();
+ while (it != that->mProcesses.end())
+ {
+ RTPROCESS pid = *it;
+ RTPROCSTATUS status;
+ int vrc = ::RTProcWait(pid, RTPROCWAIT_FLAGS_NOBLOCK, &status);
+ if (vrc == VINF_SUCCESS)
+ {
+ if ( status.enmReason != RTPROCEXITREASON_NORMAL
+ || status.iStatus != RTEXITCODE_SUCCESS)
+ {
+ switch (status.enmReason)
+ {
+ default:
+ case RTPROCEXITREASON_NORMAL:
+ LogRel(("Reaper: Pid %d (%x) exited normally: %d (%#x)\n",
+ pid, pid, status.iStatus, status.iStatus));
+ break;
+ case RTPROCEXITREASON_ABEND:
+ LogRel(("Reaper: Pid %d (%x) abended: %d (%#x)\n",
+ pid, pid, status.iStatus, status.iStatus));
+ break;
+ case RTPROCEXITREASON_SIGNAL:
+ LogRel(("Reaper: Pid %d (%x) was signalled: %d (%#x)\n",
+ pid, pid, status.iStatus, status.iStatus));
+ break;
+ }
+ }
+ else
+ LogFlowFunc(("pid %d (%x) was reaped, status=%d, reason=%d\n",
+ pid, pid, status.iStatus,
+ status.enmReason));
+ it = that->mProcesses.erase(it);
+ }
+ else
+ {
+ LogFlowFunc(("pid %d (%x) was NOT reaped, vrc=%Rrc\n",
+ pid, pid, vrc));
+ if (vrc != VERR_PROCESS_RUNNING)
+ {
+ /* remove the process if it is not already running */
+ it = that->mProcesses.erase(it);
+ }
+ else
+ ++it;
+ }
+ }
+ }
+ }
+ }
+ while (true);
+ }
+ while (0);
+
+ /* release sets of machines if any */
+ machines.clear();
+ spawnedMachines.clear();
+
+#else
+# error "Port me!"
+#endif
+
+ VirtualBoxBase::uninitializeComForThread();
+
+ LogFlowFuncLeave();
+ return 0;
+}
+/* vi: set tabstop=4 shiftwidth=4 expandtab: */
diff --git a/src/VBox/Main/src-server/DHCPServerImpl.cpp b/src/VBox/Main/src-server/DHCPServerImpl.cpp
index 45f21370..1cd7ce78 100644
--- a/src/VBox/Main/src-server/DHCPServerImpl.cpp
+++ b/src/VBox/Main/src-server/DHCPServerImpl.cpp
@@ -6,7 +6,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -17,34 +17,65 @@
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
-#include "DHCPServerRunner.h"
+#include <string>
+#include "NetworkServiceRunner.h"
#include "DHCPServerImpl.h"
#include "AutoCaller.h"
#include "Logging.h"
#include <iprt/cpp/utils.h>
+#include <VBox/com/array.h>
#include <VBox/settings.h>
#include "VirtualBoxImpl.h"
// constructor / destructor
/////////////////////////////////////////////////////////////////////////////
+const std::string DHCPServerRunner::kDsrKeyGateway = "--gateway";
+const std::string DHCPServerRunner::kDsrKeyLowerIp = "--lower-ip";
+const std::string DHCPServerRunner::kDsrKeyUpperIp = "--upper-ip";
+
+
+struct DHCPServer::Data
+{
+ Data() : enabled(FALSE) {}
+
+ Bstr IPAddress;
+ Bstr lowerIP;
+ Bstr upperIP;
+
+ BOOL enabled;
+ DHCPServerRunner dhcp;
+
+ DhcpOptionMap GlobalDhcpOptions;
+ VmSlot2OptionsMap VmSlot2Options;
+};
+
DHCPServer::DHCPServer()
- : mVirtualBox(NULL)
+ : m(NULL), mVirtualBox(NULL)
{
+ m = new DHCPServer::Data();
}
+
DHCPServer::~DHCPServer()
{
+ if (m)
+ {
+ delete m;
+ m = NULL;
+ }
}
+
HRESULT DHCPServer::FinalConstruct()
{
return BaseFinalConstruct();
}
+
void DHCPServer::FinalRelease()
{
uninit ();
@@ -52,6 +83,7 @@ void DHCPServer::FinalRelease()
BaseFinalRelease();
}
+
void DHCPServer::uninit()
{
/* Enclose the state transition Ready->InUninit->NotReady */
@@ -62,6 +94,7 @@ void DHCPServer::uninit()
unconst(mVirtualBox) = NULL;
}
+
HRESULT DHCPServer::init(VirtualBox *aVirtualBox, IN_BSTR aName)
{
AssertReturn(aName != NULL, E_INVALIDARG);
@@ -73,11 +106,12 @@ HRESULT DHCPServer::init(VirtualBox *aVirtualBox, IN_BSTR aName)
unconst(mVirtualBox) = aVirtualBox;
unconst(mName) = aName;
- m.IPAddress = "0.0.0.0";
- m.networkMask = "0.0.0.0";
- m.enabled = FALSE;
- m.lowerIP = "0.0.0.0";
- m.upperIP = "0.0.0.0";
+ m->IPAddress = "0.0.0.0";
+ m->GlobalDhcpOptions.insert(DhcpOptValuePair(DhcpOpt_SubnetMask, Bstr("0.0.0.0")));
+ m->enabled = FALSE;
+
+ m->lowerIP = "0.0.0.0";
+ m->upperIP = "0.0.0.0";
/* Confirm a successful initialization */
autoInitSpan.setSucceeded();
@@ -85,6 +119,7 @@ HRESULT DHCPServer::init(VirtualBox *aVirtualBox, IN_BSTR aName)
return S_OK;
}
+
HRESULT DHCPServer::init(VirtualBox *aVirtualBox,
const settings::DHCPServer &data)
{
@@ -96,17 +131,25 @@ HRESULT DHCPServer::init(VirtualBox *aVirtualBox,
unconst(mVirtualBox) = aVirtualBox;
unconst(mName) = data.strNetworkName;
- m.IPAddress = data.strIPAddress;
- m.networkMask = data.strIPNetworkMask;
- m.enabled = data.fEnabled;
- m.lowerIP = data.strIPLower;
- m.upperIP = data.strIPUpper;
+ m->IPAddress = data.strIPAddress;
+ m->enabled = data.fEnabled;
+ m->lowerIP = data.strIPLower;
+ m->upperIP = data.strIPUpper;
+
+ m->GlobalDhcpOptions.clear();
+ m->GlobalDhcpOptions.insert(data.GlobalDhcpOptions.begin(),
+ data.GlobalDhcpOptions.end());
+
+ m->VmSlot2Options.clear();
+ m->VmSlot2Options.insert(data.VmSlot2OptionsM.begin(),
+ data.VmSlot2OptionsM.end());
autoInitSpan.setSucceeded();
return S_OK;
}
+
HRESULT DHCPServer::saveSettings(settings::DHCPServer &data)
{
AutoCaller autoCaller(this);
@@ -115,15 +158,24 @@ HRESULT DHCPServer::saveSettings(settings::DHCPServer &data)
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
data.strNetworkName = mName;
- data.strIPAddress = m.IPAddress;
- data.strIPNetworkMask = m.networkMask;
- data.fEnabled = !!m.enabled;
- data.strIPLower = m.lowerIP;
- data.strIPUpper = m.upperIP;
+ data.strIPAddress = m->IPAddress;
+
+ data.fEnabled = !!m->enabled;
+ data.strIPLower = m->lowerIP;
+ data.strIPUpper = m->upperIP;
+
+ data.GlobalDhcpOptions.clear();
+ data.GlobalDhcpOptions.insert(m->GlobalDhcpOptions.begin(),
+ m->GlobalDhcpOptions.end());
+
+ data.VmSlot2OptionsM.clear();
+ data.VmSlot2OptionsM.insert(m->VmSlot2Options.begin(),
+ m->VmSlot2Options.end());
return S_OK;
}
+
STDMETHODIMP DHCPServer::COMGETTER(NetworkName) (BSTR *aName)
{
CheckComArgOutPointerValid(aName);
@@ -136,6 +188,7 @@ STDMETHODIMP DHCPServer::COMGETTER(NetworkName) (BSTR *aName)
return S_OK;
}
+
STDMETHODIMP DHCPServer::COMGETTER(Enabled) (BOOL *aEnabled)
{
CheckComArgOutPointerValid(aEnabled);
@@ -143,18 +196,19 @@ STDMETHODIMP DHCPServer::COMGETTER(Enabled) (BOOL *aEnabled)
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
- *aEnabled = m.enabled;
+ *aEnabled = m->enabled;
return S_OK;
}
+
STDMETHODIMP DHCPServer::COMSETTER(Enabled) (BOOL aEnabled)
{
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
- m.enabled = aEnabled;
+ m->enabled = aEnabled;
// save the global settings; for that we should hold only the VirtualBox lock
alock.release();
@@ -164,6 +218,7 @@ STDMETHODIMP DHCPServer::COMSETTER(Enabled) (BOOL aEnabled)
return rc;
}
+
STDMETHODIMP DHCPServer::COMGETTER(IPAddress) (BSTR *aIPAddress)
{
CheckComArgOutPointerValid(aIPAddress);
@@ -171,11 +226,12 @@ STDMETHODIMP DHCPServer::COMGETTER(IPAddress) (BSTR *aIPAddress)
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
- m.IPAddress.cloneTo(aIPAddress);
+ m->IPAddress.cloneTo(aIPAddress);
return S_OK;
}
+
STDMETHODIMP DHCPServer::COMGETTER(NetworkMask) (BSTR *aNetworkMask)
{
CheckComArgOutPointerValid(aNetworkMask);
@@ -183,11 +239,12 @@ STDMETHODIMP DHCPServer::COMGETTER(NetworkMask) (BSTR *aNetworkMask)
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
- m.networkMask.cloneTo(aNetworkMask);
+ m->GlobalDhcpOptions[DhcpOpt_SubnetMask].cloneTo(aNetworkMask);
return S_OK;
}
+
STDMETHODIMP DHCPServer::COMGETTER(LowerIP) (BSTR *aIPAddress)
{
CheckComArgOutPointerValid(aIPAddress);
@@ -195,11 +252,12 @@ STDMETHODIMP DHCPServer::COMGETTER(LowerIP) (BSTR *aIPAddress)
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
- m.lowerIP.cloneTo(aIPAddress);
+ m->lowerIP.cloneTo(aIPAddress);
return S_OK;
}
+
STDMETHODIMP DHCPServer::COMGETTER(UpperIP) (BSTR *aIPAddress)
{
CheckComArgOutPointerValid(aIPAddress);
@@ -207,11 +265,12 @@ STDMETHODIMP DHCPServer::COMGETTER(UpperIP) (BSTR *aIPAddress)
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
- m.upperIP.cloneTo(aIPAddress);
+ m->upperIP.cloneTo(aIPAddress);
return S_OK;
}
+
STDMETHODIMP DHCPServer::SetConfiguration (IN_BSTR aIPAddress, IN_BSTR aNetworkMask, IN_BSTR aLowerIP, IN_BSTR aUpperIP)
{
AssertReturn(aIPAddress != NULL, E_INVALIDARG);
@@ -223,10 +282,11 @@ STDMETHODIMP DHCPServer::SetConfiguration (IN_BSTR aIPAddress, IN_BSTR aNetworkM
if (FAILED(autoCaller.rc())) return autoCaller.rc();
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
- m.IPAddress = aIPAddress;
- m.networkMask = aNetworkMask;
- m.lowerIP = aLowerIP;
- m.upperIP = aUpperIP;
+ m->IPAddress = aIPAddress;
+ m->GlobalDhcpOptions[DhcpOpt_SubnetMask] = aNetworkMask;
+
+ m->lowerIP = aLowerIP;
+ m->upperIP = aUpperIP;
// save the global settings; for that we should hold only the VirtualBox lock
alock.release();
@@ -234,43 +294,251 @@ STDMETHODIMP DHCPServer::SetConfiguration (IN_BSTR aIPAddress, IN_BSTR aNetworkM
return mVirtualBox->saveSettings();
}
+
+STDMETHODIMP DHCPServer::AddGlobalOption(DhcpOpt_T aOption, IN_BSTR aValue)
+{
+ CheckComArgStr(aValue);
+ /* store global option */
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ m->GlobalDhcpOptions.insert(
+ DhcpOptValuePair(aOption, Utf8Str(aValue)));
+
+ /* Indirect way to understand that we're on NAT network */
+ if (aOption == DhcpOpt_Router)
+ m->dhcp.setOption(NetworkServiceRunner::kNsrKeyNeedMain, "on");
+
+ alock.release();
+
+ AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
+ return mVirtualBox->saveSettings();
+}
+
+
+STDMETHODIMP DHCPServer::COMGETTER(GlobalOptions)(ComSafeArrayOut(BSTR, aValue))
+{
+ CheckComArgOutSafeArrayPointerValid(aValue);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ SafeArray<BSTR> sf(m->GlobalDhcpOptions.size());
+ int i = 0;
+
+ for (DhcpOptIterator it = m->GlobalDhcpOptions.begin();
+ it != m->GlobalDhcpOptions.end(); ++it)
+ {
+ Bstr(Utf8StrFmt("%d:%s", (*it).first, (*it).second.c_str())).detachTo(&sf[i]);
+ i++;
+ }
+
+ sf.detachTo(ComSafeArrayOutArg(aValue));
+
+ return S_OK;
+}
+
+
+STDMETHODIMP DHCPServer::COMGETTER(VmConfigs)(ComSafeArrayOut(BSTR, aValue))
+{
+ CheckComArgOutSafeArrayPointerValid(aValue);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ SafeArray<BSTR> sf(m->VmSlot2Options.size());
+ VmSlot2OptionsIterator it = m->VmSlot2Options.begin();
+ int i = 0;
+ for (;it != m->VmSlot2Options.end(); ++it)
+ {
+ Bstr(Utf8StrFmt("[%s]:%d",
+ it->first.VmName.c_str(),
+ it->first.Slot)).detachTo(&sf[i]);
+ i++;
+ }
+
+ sf.detachTo(ComSafeArrayOutArg(aValue));
+
+ return S_OK;
+}
+
+
+STDMETHODIMP DHCPServer::AddVmSlotOption(IN_BSTR aVmName, LONG aSlot, DhcpOpt_T aOption, IN_BSTR aValue)
+{
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ m->VmSlot2Options[settings::VmNameSlotKey(
+ com::Utf8Str(aVmName),
+ aSlot)][aOption] = com::Utf8Str(aValue);
+
+
+ alock.release();
+
+ AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
+ return mVirtualBox->saveSettings();
+}
+
+
+STDMETHODIMP DHCPServer::RemoveVmSlotOptions(IN_BSTR aVmName, LONG aSlot)
+{
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ DhcpOptionMap& map = findOptMapByVmNameSlot(com::Utf8Str(aVmName), aSlot);
+
+ map.clear();
+
+ alock.release();
+
+ AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
+ return mVirtualBox->saveSettings();
+}
+
+
+/**
+ * this is mapping (vm, slot)
+ */
+STDMETHODIMP DHCPServer::GetVmSlotOptions(IN_BSTR aVmName,
+ LONG aSlot,
+ ComSafeArrayOut(BSTR, aValues))
+{
+ CheckComArgOutSafeArrayPointerValid(aValues);
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ DhcpOptionMap& map = findOptMapByVmNameSlot(com::Utf8Str(aVmName), aSlot);
+
+ SafeArray<BSTR> sf(map.size());
+ int i = 0;
+
+ for (DhcpOptIterator it = map.begin();
+ it != map.end(); ++it)
+ {
+ Bstr(Utf8StrFmt("%d:%s", (*it).first, (*it).second.c_str())).detachTo(&sf[i]);
+ i++;
+ }
+
+ sf.detachTo(ComSafeArrayOutArg(aValues));
+
+ return S_OK;
+}
+
+
+STDMETHODIMP DHCPServer::GetMacOptions(IN_BSTR aMAC, ComSafeArrayOut(BSTR, aValues))
+{
+ CheckComArgOutSafeArrayPointerValid(aValues);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+ HRESULT hrc = S_OK;
+
+ ComPtr<IMachine> machine;
+ ComPtr<INetworkAdapter> nic;
+
+ VmSlot2OptionsIterator it;
+ for(it = m->VmSlot2Options.begin();
+ it != m->VmSlot2Options.end();
+ ++it)
+ {
+
+ alock.release();
+ hrc = mVirtualBox->FindMachine(Bstr(it->first.VmName).raw(), machine.asOutParam());
+ alock.acquire();
+
+ if (FAILED(hrc))
+ continue;
+
+ alock.release();
+ hrc = machine->GetNetworkAdapter(it->first.Slot, nic.asOutParam());
+ alock.acquire();
+
+ if (FAILED(hrc))
+ continue;
+
+ com::Bstr mac;
+
+ alock.release();
+ hrc = nic->COMGETTER(MACAddress)(mac.asOutParam());
+ alock.acquire();
+
+ if (FAILED(hrc)) /* no MAC address ??? */
+ break;
+
+ if (!RTStrICmp(com::Utf8Str(mac).c_str(), com::Utf8Str(aMAC).c_str()))
+ return GetVmSlotOptions(Bstr(it->first.VmName).raw(),
+ it->first.Slot,
+ ComSafeArrayOutArg(aValues));
+ } /* end of for */
+
+ return hrc;
+}
+
+
+STDMETHODIMP DHCPServer::COMGETTER(EventSource)(IEventSource **aEventSource)
+{
+ NOREF(aEventSource);
+ ReturnComNotImplemented();
+}
+
+
STDMETHODIMP DHCPServer::Start(IN_BSTR aNetworkName, IN_BSTR aTrunkName, IN_BSTR aTrunkType)
{
/* Silently ignore attempts to run disabled servers. */
- if (!m.enabled)
+ if (!m->enabled)
return S_OK;
- m.dhcp.setOption(DHCPCFG_NETNAME, Utf8Str(aNetworkName), true);
+ /* Commmon Network Settings */
+ m->dhcp.setOption(NetworkServiceRunner::kNsrKeyNetwork, Utf8Str(aNetworkName).c_str());
+
Bstr tmp(aTrunkName);
+
if (!tmp.isEmpty())
- m.dhcp.setOption(DHCPCFG_TRUNKNAME, Utf8Str(tmp), true);
- m.dhcp.setOption(DHCPCFG_TRUNKTYPE, Utf8Str(aTrunkType), true);
- //temporary hack for testing
- // DHCPCFG_NAME
+ m->dhcp.setOption(NetworkServiceRunner::kNsrTrunkName, Utf8Str(tmp).c_str());
+ m->dhcp.setOption(NetworkServiceRunner::kNsrKeyTrunkType, Utf8Str(aTrunkType).c_str());
+
+ /* XXX: should this MAC default initialization moved to NetworkServiceRunner? */
char strMAC[32];
Guid guid;
guid.create();
RTStrPrintf (strMAC, sizeof(strMAC), "08:00:27:%02X:%02X:%02X",
- guid.raw()->au8[0], guid.raw()->au8[1], guid.raw()->au8[2]);
- m.dhcp.setOption(DHCPCFG_MACADDRESS, strMAC, true);
- m.dhcp.setOption(DHCPCFG_IPADDRESS, Utf8Str(m.IPAddress), true);
- // DHCPCFG_LEASEDB,
- // DHCPCFG_VERBOSE,
- // DHCPCFG_GATEWAY,
- m.dhcp.setOption(DHCPCFG_LOWERIP, Utf8Str(m.lowerIP), true);
- m.dhcp.setOption(DHCPCFG_UPPERIP, Utf8Str(m.upperIP), true);
- m.dhcp.setOption(DHCPCFG_NETMASK, Utf8Str(m.networkMask), true);
-
- // DHCPCFG_HELP,
- // DHCPCFG_VERSION,
- // DHCPCFG_NOTOPT_MAXVAL
- m.dhcp.setOption(DHCPCFG_BEGINCONFIG, "", true);
-
- return RT_FAILURE(m.dhcp.start()) ? E_FAIL : S_OK;
- //m.dhcp.detachFromServer(); /* need to do this to avoid server shutdown on runner destruction */
+ guid.raw()->au8[0],
+ guid.raw()->au8[1],
+ guid.raw()->au8[2]);
+ m->dhcp.setOption(NetworkServiceRunner::kNsrMacAddress, strMAC);
+ m->dhcp.setOption(NetworkServiceRunner::kNsrIpAddress, Utf8Str(m->IPAddress).c_str());
+ m->dhcp.setOption(NetworkServiceRunner::kNsrIpNetmask, Utf8Str(m->GlobalDhcpOptions[DhcpOpt_SubnetMask]).c_str());
+ m->dhcp.setOption(DHCPServerRunner::kDsrKeyLowerIp, Utf8Str(m->lowerIP).c_str());
+ m->dhcp.setOption(DHCPServerRunner::kDsrKeyUpperIp, Utf8Str(m->upperIP).c_str());
+
+ /* XXX: This parameters Dhcp Server will fetch via API */
+ return RT_FAILURE(m->dhcp.start()) ? E_FAIL : S_OK;
+ //m->dhcp.detachFromServer(); /* need to do this to avoid server shutdown on runner destruction */
}
+
STDMETHODIMP DHCPServer::Stop (void)
{
- return RT_FAILURE(m.dhcp.stop()) ? E_FAIL : S_OK;
+ return RT_FAILURE(m->dhcp.stop()) ? E_FAIL : S_OK;
+}
+
+
+DhcpOptionMap& DHCPServer::findOptMapByVmNameSlot(const com::Utf8Str& aVmName,
+ LONG aSlot)
+{
+ return m->VmSlot2Options[settings::VmNameSlotKey(
+ com::Utf8Str(aVmName),
+ aSlot)];
}
diff --git a/src/VBox/Main/src-server/HostDnsService.cpp b/src/VBox/Main/src-server/HostDnsService.cpp
new file mode 100644
index 00000000..011528fb
--- /dev/null
+++ b/src/VBox/Main/src-server/HostDnsService.cpp
@@ -0,0 +1,363 @@
+/* $Id: HostDnsService.cpp $ */
+/** @file
+ * Base class fo Host DNS & Co services.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include <VBox/com/array.h>
+#include <VBox/com/ptr.h>
+#include <VBox/com/string.h>
+
+#include <iprt/cpp/utils.h>
+
+#include "Logging.h"
+#include "VirtualBoxImpl.h"
+#include <iprt/thread.h>
+#include <iprt/semaphore.h>
+#include <iprt/critsect.h>
+
+#include <algorithm>
+#include <string>
+#include "HostDnsService.h"
+
+
+static HostDnsMonitor *g_monitor;
+
+static void dumpHostDnsInformation(const HostDnsInformation&);
+static void dumpHostDnsStrVector(const std::string&, const std::vector<std::string>&);
+
+/* Lockee */
+Lockee::Lockee()
+{
+ RTCritSectInit(&mLock);
+}
+
+Lockee::~Lockee()
+{
+ RTCritSectDelete(&mLock);
+}
+
+const RTCRITSECT* Lockee::lock() const
+{
+ return &mLock;
+}
+
+/* ALock */
+ALock::ALock(const Lockee *aLockee)
+ : lockee(aLockee)
+{
+ RTCritSectEnter(const_cast<PRTCRITSECT>(lockee->lock()));
+}
+
+ALock::~ALock()
+{
+ RTCritSectLeave(const_cast<PRTCRITSECT>(lockee->lock()));
+}
+
+inline static void detachVectorOfString(const std::vector<std::string>& v,
+ ComSafeArrayOut(BSTR, aBstrArray))
+{
+ com::SafeArray<BSTR> aBstr(v.size());
+
+ std::vector<std::string>::const_iterator it;
+
+ int i = 0;
+ it = v.begin();
+ for (; it != v.end(); ++it, ++i)
+ Utf8Str(it->c_str()).cloneTo(&aBstr[i]);
+
+ aBstr.detachTo(ComSafeArrayOutArg(aBstrArray));
+}
+
+struct HostDnsMonitor::Data
+{
+ Data(bool aThreaded):fThreaded(aThreaded){}
+
+ std::vector<PCHostDnsMonitorProxy> proxies;
+ HostDnsInformation info;
+ const bool fThreaded;
+ RTTHREAD hMonitoringThread;
+ RTSEMEVENT hDnsInitEvent;
+};
+
+struct HostDnsMonitorProxy::Data
+{
+ Data(const HostDnsMonitor *aMonitor, const VirtualBox *aParent)
+ : info(NULL)
+ , virtualbox(aParent)
+ , monitor(aMonitor)
+ , fModified(true)
+ {}
+
+ virtual ~Data()
+ {
+ if (info)
+ {
+ delete info;
+ info = NULL;
+ }
+ }
+
+ HostDnsInformation *info;
+ const VirtualBox *virtualbox;
+ const HostDnsMonitor *monitor;
+ bool fModified;
+};
+
+
+HostDnsMonitor::HostDnsMonitor(bool fThreaded)
+ : m(NULL)
+{
+ m = new HostDnsMonitor::Data(fThreaded);
+}
+
+HostDnsMonitor::~HostDnsMonitor()
+{
+ if (m)
+ {
+ delete m;
+ m = NULL;
+ }
+}
+
+const HostDnsMonitor *HostDnsMonitor::getHostDnsMonitor()
+{
+ /* XXX: Moved initialization from HostImpl.cpp */
+ if (!g_monitor)
+ {
+# if defined (RT_OS_DARWIN)
+ g_monitor = new HostDnsServiceDarwin();
+# elif defined(RT_OS_WINDOWS)
+ g_monitor = new HostDnsServiceWin();
+# elif defined(RT_OS_LINUX)
+ g_monitor = new HostDnsServiceLinux();
+# elif defined(RT_OS_SOLARIS)
+ g_monitor = new HostDnsServiceSolaris();
+# elif defined(RT_OS_FREEBSD)
+ g_monitor = new HostDnsServiceFreebsd();
+# elif defined(RT_OS_OS2)
+ g_monitor = new HostDnsServiceOs2();
+# else
+ g_monitor = new HostDnsService();
+# endif
+ g_monitor->init();
+ }
+
+ return g_monitor;
+}
+
+void HostDnsMonitor::addMonitorProxy(PCHostDnsMonitorProxy proxy) const
+{
+ ALock l(this);
+ m->proxies.push_back(proxy);
+ proxy->notify();
+}
+
+void HostDnsMonitor::releaseMonitorProxy(PCHostDnsMonitorProxy proxy) const
+{
+ ALock l(this);
+ std::vector<PCHostDnsMonitorProxy>::iterator it;
+ it = std::find(m->proxies.begin(), m->proxies.end(), proxy);
+
+ if (it == m->proxies.end())
+ return;
+
+ m->proxies.erase(it);
+}
+
+void HostDnsMonitor::shutdown()
+{
+ if (g_monitor)
+ {
+ delete g_monitor;
+ g_monitor = NULL;
+ }
+}
+
+const HostDnsInformation &HostDnsMonitor::getInfo() const
+{
+ return m->info;
+}
+
+void HostDnsMonitor::notifyAll() const
+{
+ ALock l(this);
+ std::vector<PCHostDnsMonitorProxy>::const_iterator it;
+ for (it = m->proxies.begin(); it != m->proxies.end(); ++it)
+ (*it)->notify();
+}
+
+void HostDnsMonitor::setInfo(const HostDnsInformation &info)
+{
+ ALock l(this);
+ m->info = info;
+}
+
+HRESULT HostDnsMonitor::init()
+{
+ if (m->fThreaded)
+ {
+ int rc = RTSemEventCreate(&m->hDnsInitEvent);
+ AssertRCReturn(rc, E_FAIL);
+
+ rc = RTThreadCreate(&m->hMonitoringThread,
+ HostDnsMonitor::threadMonitoringRoutine,
+ this, 128 * _1K, RTTHREADTYPE_IO, 0, "dns-monitor");
+ AssertRCReturn(rc, E_FAIL);
+
+ RTSemEventWait(m->hDnsInitEvent, RT_INDEFINITE_WAIT);
+ }
+ return S_OK;
+}
+
+
+void HostDnsMonitor::monitorThreadInitializationDone()
+{
+ RTSemEventSignal(m->hDnsInitEvent);
+}
+
+
+int HostDnsMonitor::threadMonitoringRoutine(RTTHREAD, void *pvUser)
+{
+ HostDnsMonitor *pThis = static_cast<HostDnsMonitor *>(pvUser);
+ return pThis->monitorWorker();
+}
+
+/* HostDnsMonitorProxy */
+HostDnsMonitorProxy::HostDnsMonitorProxy()
+ : m(NULL)
+{
+}
+
+HostDnsMonitorProxy::~HostDnsMonitorProxy()
+{
+ if (m)
+ {
+ if (m->monitor)
+ m->monitor->releaseMonitorProxy(this);
+ delete m;
+ m = NULL;
+ }
+}
+
+void HostDnsMonitorProxy::init(const HostDnsMonitor *mon, const VirtualBox* aParent)
+{
+ m = new HostDnsMonitorProxy::Data(mon, aParent);
+ m->monitor->addMonitorProxy(this);
+ updateInfo();
+}
+
+void HostDnsMonitorProxy::notify() const
+{
+ m->fModified = true;
+ const_cast<VirtualBox *>(m->virtualbox)->onHostNameResolutionConfigurationChange();
+}
+
+HRESULT HostDnsMonitorProxy::GetNameServers(ComSafeArrayOut(BSTR, aNameServers))
+{
+ AssertReturn(m && m->info, E_FAIL);
+ ALock l(this);
+
+ if (m->fModified)
+ updateInfo();
+
+ LogRel(("HostDnsMonitorProxy::GetNameServers:\n"));
+ dumpHostDnsStrVector("Name Server", m->info->servers);
+
+ detachVectorOfString(m->info->servers, ComSafeArrayOutArg(aNameServers));
+
+ return S_OK;
+}
+
+HRESULT HostDnsMonitorProxy::GetDomainName(BSTR *aDomainName)
+{
+ AssertReturn(m && m->info, E_FAIL);
+ ALock l(this);
+
+ if (m->fModified)
+ updateInfo();
+
+ LogRel(("HostDnsMonitorProxy::GetDomainName: %s\n", m->info->domain.c_str()));
+
+ Utf8Str(m->info->domain.c_str()).cloneTo(aDomainName);
+
+ return S_OK;
+}
+
+HRESULT HostDnsMonitorProxy::GetSearchStrings(ComSafeArrayOut(BSTR, aSearchStrings))
+{
+ AssertReturn(m && m->info, E_FAIL);
+ ALock l(this);
+
+ if (m->fModified)
+ updateInfo();
+
+ LogRel(("HostDnsMonitorProxy::GetSearchStrings:\n"));
+ dumpHostDnsStrVector("Search String", m->info->searchList);
+
+ detachVectorOfString(m->info->searchList, ComSafeArrayOutArg(aSearchStrings));
+
+ return S_OK;
+}
+
+bool HostDnsMonitorProxy::operator==(PCHostDnsMonitorProxy& rhs)
+{
+ if (!m || !rhs->m)
+ return false;
+
+ /**
+ * we've assigned to the same instance of VirtualBox.
+ */
+ return m->virtualbox == rhs->m->virtualbox;
+}
+
+void HostDnsMonitorProxy::updateInfo()
+{
+ HostDnsInformation *info = new HostDnsInformation(m->monitor->getInfo());
+ HostDnsInformation *old = m->info;
+
+ LogRel(("HostDnsMonitorProxy: Host's DNS information updated:\n"));
+ dumpHostDnsInformation(*info);
+
+ m->info = info;
+ if (old)
+ {
+ LogRel(("HostDnsMonitorProxy: Old host information:\n"));
+ dumpHostDnsInformation(*old);
+
+ delete old;
+ }
+
+ m->fModified = false;
+}
+
+
+static void dumpHostDnsInformation(const HostDnsInformation& info)
+{
+ dumpHostDnsStrVector("DNS server", info.servers);
+ dumpHostDnsStrVector("SearchString", info.searchList);
+
+ if (!info.domain.empty())
+ LogRel(("DNS domain: %s\n", info.domain.c_str()));
+}
+
+
+static void dumpHostDnsStrVector(const std::string& prefix, const std::vector<std::string>& v)
+{
+ int i = 1;
+ for (std::vector<std::string>::const_iterator it = v.begin();
+ it != v.end();
+ ++it, ++i)
+ LogRel(("%s %d: %s\n", prefix.c_str(), i, it->c_str()));
+}
diff --git a/src/VBox/Main/src-server/HostDnsService.h b/src/VBox/Main/src-server/HostDnsService.h
new file mode 100644
index 00000000..56da78d0
--- /dev/null
+++ b/src/VBox/Main/src-server/HostDnsService.h
@@ -0,0 +1,236 @@
+/* $Id: HostDnsService.h $ */
+/** @file
+ * Host DNS listener.
+ */
+
+/*
+ * Copyright (C) 2005-2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef ___H_DNSHOSTSERVICE
+#define ___H_DNSHOSTSERVICE
+#include "VirtualBoxBase.h"
+
+#include <iprt/cdefs.h>
+#include <iprt/critsect.h>
+#include <iprt/types.h>
+
+#include <list>
+#include <vector>
+
+typedef std::list<com::Utf8Str> Utf8StrList;
+typedef Utf8StrList::iterator Utf8StrListIterator;
+
+class HostDnsMonitorProxy;
+typedef const HostDnsMonitorProxy *PCHostDnsMonitorProxy;
+
+class Lockee
+{
+ public:
+ Lockee();
+ virtual ~Lockee();
+ const RTCRITSECT* lock() const;
+
+ private:
+ RTCRITSECT mLock;
+};
+
+class ALock
+{
+ public:
+ explicit ALock(const Lockee *l);
+ ~ALock();
+
+ private:
+ const Lockee *lockee;
+};
+
+class HostDnsInformation
+{
+ public:
+ std::vector<std::string> servers;
+ std::string domain;
+ std::vector<std::string> searchList;
+};
+
+/**
+ * This class supposed to be a real DNS monitor object it should be singleton,
+ * it lifecycle starts and ends together with VBoxSVC.
+ */
+class HostDnsMonitor : public Lockee
+{
+ public:
+ static const HostDnsMonitor *getHostDnsMonitor();
+ static void shutdown();
+
+ void addMonitorProxy(PCHostDnsMonitorProxy) const;
+ void releaseMonitorProxy(PCHostDnsMonitorProxy) const;
+ const HostDnsInformation &getInfo() const;
+ /* @note: method will wait till client call
+ HostDnsService::monitorThreadInitializationDone() */
+ virtual HRESULT init();
+
+ protected:
+ explicit HostDnsMonitor(bool fThreaded = false);
+ virtual ~HostDnsMonitor();
+
+ void notifyAll() const;
+ void setInfo(const HostDnsInformation &);
+
+ /* this function used only if HostDnsMonitor::HostDnsMonitor(true) */
+ void monitorThreadInitializationDone();
+ virtual void monitorThreadShutdown() = 0;
+ virtual int monitorWorker() = 0;
+
+ private:
+ HostDnsMonitor(const HostDnsMonitor &);
+ HostDnsMonitor& operator= (const HostDnsMonitor &);
+ static int threadMonitoringRoutine(RTTHREAD, void *);
+
+ public:
+ struct Data;
+ Data *m;
+};
+
+/**
+ * This class supposed to be a proxy for events on changing Host Name Resolving configurations.
+ */
+class HostDnsMonitorProxy : public Lockee
+{
+ public:
+ HostDnsMonitorProxy();
+ ~HostDnsMonitorProxy();
+ void init(const HostDnsMonitor *aMonitor, const VirtualBox *aParent);
+ void notify() const;
+
+ HRESULT GetNameServers(ComSafeArrayOut(BSTR, aNameServers));
+ HRESULT GetDomainName(BSTR *aDomainName);
+ HRESULT GetSearchStrings(ComSafeArrayOut(BSTR, aSearchStrings));
+
+ bool operator==(PCHostDnsMonitorProxy&);
+
+ private:
+ void updateInfo();
+
+ private:
+ struct Data;
+ Data *m;
+};
+
+# ifdef RT_OS_DARWIN
+class HostDnsServiceDarwin : public HostDnsMonitor
+{
+ public:
+ HostDnsServiceDarwin();
+ ~HostDnsServiceDarwin();
+ HRESULT init();
+
+ protected:
+ virtual void monitorThreadShutdown();
+ virtual int monitorWorker();
+
+ private:
+ HRESULT updateInfo();
+ static void hostDnsServiceStoreCallback(void *store, void *arrayRef, void *info);
+ struct Data;
+ Data *m;
+};
+# endif
+# ifdef RT_OS_WINDOWS
+class HostDnsServiceWin : public HostDnsMonitor
+{
+ public:
+ HostDnsServiceWin();
+ ~HostDnsServiceWin();
+ HRESULT init();
+
+ protected:
+ virtual void monitorThreadShutdown();
+ virtual int monitorWorker();
+
+ private:
+ void strList2List(std::vector<std::string>& lst, char *strLst);
+ HRESULT updateInfo();
+
+ private:
+ struct Data;
+ Data *m;
+};
+# endif
+# if defined(RT_OS_SOLARIS) || defined(RT_OS_LINUX) || defined(RT_OS_OS2) || defined(RT_OS_FREEBSD)
+class HostDnsServiceResolvConf: public HostDnsMonitor
+{
+ public:
+ explicit HostDnsServiceResolvConf(bool fThreaded = false) : HostDnsMonitor(fThreaded), m(NULL) {}
+ virtual ~HostDnsServiceResolvConf();
+ virtual HRESULT init(const char *aResolvConfFileName);
+ const std::string& resolvConf() const;
+
+ protected:
+ HRESULT readResolvConf();
+ /* While not all hosts supports Hosts DNS change notifiaction
+ * default implementation offers return VERR_IGNORE.
+ */
+ virtual void monitorThreadShutdown() {}
+ virtual int monitorWorker() {return VERR_IGNORED;}
+
+ protected:
+ struct Data;
+ Data *m;
+};
+# if defined(RT_OS_SOLARIS)
+/**
+ * XXX: https://blogs.oracle.com/praks/entry/file_events_notification
+ */
+class HostDnsServiceSolaris : public HostDnsServiceResolvConf
+{
+ public:
+ HostDnsServiceSolaris(){}
+ ~HostDnsServiceSolaris(){}
+ HRESULT init(){ return HostDnsServiceResolvConf::init("/etc/resolv.conf");}
+};
+
+# elif defined(RT_OS_LINUX)
+class HostDnsServiceLinux : public HostDnsServiceResolvConf
+{
+ public:
+ HostDnsServiceLinux():HostDnsServiceResolvConf(true){}
+ virtual ~HostDnsServiceLinux();
+ virtual HRESULT init(){ return HostDnsServiceResolvConf::init("/etc/resolv.conf");}
+
+ protected:
+ virtual void monitorThreadShutdown();
+ virtual int monitorWorker();
+};
+
+# elif defined(RT_OS_FREEBSD)
+class HostDnsServiceFreebsd: public HostDnsServiceResolvConf
+{
+ public:
+ HostDnsServiceFreebsd(){}
+ ~HostDnsServiceFreebsd(){}
+ HRESULT init(){ return HostDnsServiceResolvConf::init("/etc/resolv.conf");}
+};
+
+# elif defined(RT_OS_OS2)
+class HostDnsServiceOs2 : public HostDnsServiceResolvConf
+{
+ public:
+ HostDnsServiceOs2(){}
+ ~HostDnsServiceOs2(){}
+ /* XXX: \\MPTN\\ETC should be taken from environment variable ETC */
+ HRESULT init(){ return init("\\MPTN\\ETC\\RESOLV2");}
+};
+
+# endif
+# endif
+
+#endif /* !___H_DNSHOSTSERVICE */
diff --git a/src/VBox/Main/src-server/HostDnsServiceResolvConf.cpp b/src/VBox/Main/src-server/HostDnsServiceResolvConf.cpp
new file mode 100644
index 00000000..3b2ceeb8
--- /dev/null
+++ b/src/VBox/Main/src-server/HostDnsServiceResolvConf.cpp
@@ -0,0 +1,91 @@
+/* -*- indent-tabs-mode: nil; -*- */
+#include <VBox/com/string.h>
+#include <VBox/com/ptr.h>
+
+
+#ifdef RT_OS_OS2
+# include <sys/socket.h>
+typedef int socklen_t;
+#endif
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/file.h>
+#include <iprt/critsect.h>
+
+#include <VBox/log.h>
+
+#include <string>
+
+#include "HostDnsService.h"
+#include "../../Devices/Network/slirp/resolv_conf_parser.h"
+
+
+struct HostDnsServiceResolvConf::Data
+{
+ Data(const char *fileName):resolvConfFilename(fileName){};
+
+ std::string resolvConfFilename;
+};
+
+const std::string& HostDnsServiceResolvConf::resolvConf() const
+{
+ return m->resolvConfFilename;
+}
+
+
+HostDnsServiceResolvConf::~HostDnsServiceResolvConf()
+{
+ if (m)
+ {
+ delete m;
+ m = NULL;
+ }
+}
+
+HRESULT HostDnsServiceResolvConf::init(const char *aResolvConfFileName)
+{
+ m = new Data(aResolvConfFileName);
+
+ HostDnsMonitor::init();
+
+ readResolvConf();
+
+ return S_OK;
+}
+
+
+HRESULT HostDnsServiceResolvConf::readResolvConf()
+{
+ struct rcp_state st;
+
+ st.rcps_flags = RCPSF_NO_STR2IPCONV;
+ int rc = rcp_parse(&st, m->resolvConfFilename.c_str());
+ if (rc == -1)
+ return S_OK;
+
+ HostDnsInformation info;
+ for (unsigned i = 0; i != st.rcps_num_nameserver; ++i)
+ {
+ AssertBreak(st.rcps_str_nameserver[i]);
+ info.servers.push_back(st.rcps_str_nameserver[i]);
+ }
+
+ if (st.rcps_domain)
+ info.domain = st.rcps_domain;
+
+ for (unsigned i = 0; i != st.rcps_num_searchlist; ++i)
+ {
+ AssertBreak(st.rcps_searchlist[i]);
+ info.searchList.push_back(st.rcps_searchlist[i]);
+ }
+ setInfo(info);
+
+ return S_OK;
+}
diff --git a/src/VBox/Main/src-server/HostImpl.cpp b/src/VBox/Main/src-server/HostImpl.cpp
index 03f056c6..bb94c241 100644
--- a/src/VBox/Main/src-server/HostImpl.cpp
+++ b/src/VBox/Main/src-server/HostImpl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2004-2012 Oracle Corporation
+ * Copyright (C) 2004-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -30,6 +30,7 @@
#endif // VBOX_WITH_USB
#include "HostNetworkInterfaceImpl.h"
+#include "HostVideoInputDeviceImpl.h"
#include "MachineImpl.h"
#include "AutoCaller.h"
#include "Logging.h"
@@ -54,6 +55,11 @@
# include <VBox/VBoxNetCfg-win.h>
#endif /* #if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT) */
+#if defined(RT_OS_DARWIN) && ARCH_BITS == 32
+# include <sys/types.h>
+# include <sys/sysctl.h>
+#endif
+
#ifdef RT_OS_LINUX
# include <sys/ioctl.h>
# include <errno.h>
@@ -133,15 +139,17 @@ typedef SOLARISDVD *PSOLARISDVD;
#include <iprt/env.h>
#include <iprt/mem.h>
#include <iprt/system.h>
-#ifdef RT_OS_SOLARIS
+#ifndef RT_OS_WINDOWS
# include <iprt/path.h>
+#endif
+#ifdef RT_OS_SOLARIS
# include <iprt/ctype.h>
#endif
#ifdef VBOX_WITH_HOSTNETIF_API
# include "netif.h"
#endif
-/* XXX Solaris: definitions in /usr/include/sys/regset.h clash with hwacc_svm.h */
+/* XXX Solaris: definitions in /usr/include/sys/regset.h clash with hm_svm.h */
#undef DS
#undef ES
#undef CS
@@ -150,17 +158,22 @@ typedef SOLARISDVD *PSOLARISDVD;
#undef GS
#include <VBox/usb.h>
-#include <VBox/vmm/hwacc_svm.h>
+#include <VBox/vmm/hm_svm.h>
#include <VBox/err.h>
#include <VBox/settings.h>
#include <VBox/sup.h>
#include <iprt/x86.h>
#include "VBox/com/MultiResult.h"
+#include "VBox/com/array.h"
#include <stdio.h>
#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "HostDnsService.h"
////////////////////////////////////////////////////////////////////////////////
//
@@ -199,19 +212,24 @@ struct Host::Data
/** Object with information about host drives */
VBoxMainDriveInfo hostDrives;
#endif
- /* Features that can be queried with GetProcessorFeature */
- BOOL fVTSupported,
+ /** @name Features that can be queried with GetProcessorFeature.
+ * @{ */
+ bool fVTSupported,
fLongModeSupported,
fPAESupported,
- fNestedPagingSupported;
+ fNestedPagingSupported,
+ fRecheckVTSupported;
- /* 3D hardware acceleration supported? */
- BOOL f3DAccelerationSupported;
+ /** @} */
+
+ /** 3D hardware acceleration supported? Tristate, -1 meaning not probed. */
+ int f3DAccelerationSupported;
HostPowerService *pHostPowerService;
+ /** Host's DNS informaton fetching */
+ HostDnsMonitorProxy hostDnsMonitorProxy;
};
-
////////////////////////////////////////////////////////////////////////////////
//
// Constructor / destructor
@@ -276,6 +294,8 @@ HRESULT Host::init(VirtualBox *aParent)
/* Create the list of network interfaces so their metrics get registered. */
updateNetIfList();
+ m->hostDnsMonitorProxy.init(HostDnsMonitor::getHostDnsMonitor(), m->pParent);
+
#if defined (RT_OS_WINDOWS)
m->pHostPowerService = new HostPowerServiceWin(m->pParent);
#elif defined (RT_OS_DARWIN)
@@ -289,100 +309,104 @@ HRESULT Host::init(VirtualBox *aParent)
m->fLongModeSupported = false;
m->fPAESupported = false;
m->fNestedPagingSupported = false;
+ m->fRecheckVTSupported = false;
if (ASMHasCpuId())
{
- uint32_t u32FeaturesECX;
- uint32_t u32Dummy;
- uint32_t u32FeaturesEDX;
- uint32_t u32VendorEBX, u32VendorECX, u32VendorEDX, u32ExtFeatureEDX, u32ExtFeatureECX;
-
- ASMCpuId(0, &u32Dummy, &u32VendorEBX, &u32VendorECX, &u32VendorEDX);
- ASMCpuId(1, &u32Dummy, &u32Dummy, &u32FeaturesECX, &u32FeaturesEDX);
- /* Query Extended features. */
- ASMCpuId(0x80000001, &u32Dummy, &u32Dummy, &u32ExtFeatureECX, &u32ExtFeatureEDX);
-
- m->fLongModeSupported = !!(u32ExtFeatureEDX & X86_CPUID_EXT_FEATURE_EDX_LONG_MODE);
- m->fPAESupported = !!(u32FeaturesEDX & X86_CPUID_FEATURE_EDX_PAE);
-
- if ( u32VendorEBX == X86_CPUID_VENDOR_INTEL_EBX
- && u32VendorECX == X86_CPUID_VENDOR_INTEL_ECX
- && u32VendorEDX == X86_CPUID_VENDOR_INTEL_EDX
- )
+ /* Note! This code is duplicated in SUPDrv.c and other places! */
+ uint32_t uMaxId, uVendorEBX, uVendorECX, uVendorEDX;
+ ASMCpuId(0, &uMaxId, &uVendorEBX, &uVendorECX, &uVendorEDX);
+ if (ASMIsValidStdRange(uMaxId))
{
- /* Intel. */
- if ( (u32FeaturesECX & X86_CPUID_FEATURE_ECX_VMX)
- && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR)
- && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR)
- )
- {
- int rc = SUPR3QueryVTxSupported();
- if (RT_SUCCESS(rc))
- m->fVTSupported = true;
- }
- }
- else
- if ( u32VendorEBX == X86_CPUID_VENDOR_AMD_EBX
- && u32VendorECX == X86_CPUID_VENDOR_AMD_ECX
- && u32VendorEDX == X86_CPUID_VENDOR_AMD_EDX
- )
- {
- /* AMD. */
- if ( (u32ExtFeatureECX & X86_CPUID_AMD_FEATURE_ECX_SVM)
- && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR)
- && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR)
- )
- {
- uint32_t u32SVMFeatureEDX;
-
- m->fVTSupported = true;
+ /* PAE? */
+ uint32_t uDummy, fFeaturesEcx, fFeaturesEdx;
+ ASMCpuId(1, &uDummy, &uDummy, &fFeaturesEcx, &fFeaturesEdx);
+ m->fPAESupported = RT_BOOL(fFeaturesEdx & X86_CPUID_FEATURE_EDX_PAE);
+
+ /* Long Mode? */
+ uint32_t uExtMaxId, fExtFeaturesEcx, fExtFeaturesEdx;
+ ASMCpuId(0x80000000, &uExtMaxId, &uDummy, &uDummy, &uDummy);
+ ASMCpuId(0x80000001, &uDummy, &uDummy, &fExtFeaturesEcx, &fExtFeaturesEdx);
+ m->fLongModeSupported = ASMIsValidExtRange(uExtMaxId)
+ && (fExtFeaturesEdx & X86_CPUID_EXT_FEATURE_EDX_LONG_MODE);
+
+#if defined(RT_OS_DARWIN) && ARCH_BITS == 32 /* darwin.x86 has some optimizations of 64-bit on 32-bit. */
+ int f64bitCapable = 0;
+ size_t cbParameter = sizeof(f64bitCapable);
+ if (sysctlbyname("hw.cpu64bit_capable", &f64bitCapable, &cbParameter, NULL, NULL) != -1)
+ m->fLongModeSupported = f64bitCapable != 0;
+#endif
- /* Query AMD features. */
- ASMCpuId(0x8000000A, &u32Dummy, &u32Dummy, &u32Dummy, &u32SVMFeatureEDX);
- if (u32SVMFeatureEDX & AMD_CPUID_SVM_FEATURE_EDX_NESTED_PAGING)
- m->fNestedPagingSupported = true;
+ /* VT-x? */
+ if ( ASMIsIntelCpuEx(uVendorEBX, uVendorECX, uVendorEDX)
+ || ASMIsViaCentaurCpuEx(uVendorEBX, uVendorECX, uVendorEDX))
+ {
+ if ( (fFeaturesEcx & X86_CPUID_FEATURE_ECX_VMX)
+ && (fFeaturesEdx & X86_CPUID_FEATURE_EDX_MSR)
+ && (fFeaturesEdx & X86_CPUID_FEATURE_EDX_FXSR)
+ )
+ {
+ int rc = SUPR3QueryVTxSupported();
+ if (RT_SUCCESS(rc))
+ m->fVTSupported = true;
+ }
}
- }
- else
- if ( u32VendorEBX == X86_CPUID_VENDOR_VIA_EBX
- && u32VendorECX == X86_CPUID_VENDOR_VIA_ECX
- && u32VendorEDX == X86_CPUID_VENDOR_VIA_EDX
- )
- {
- /* VIA. */
- if ( (u32FeaturesECX & X86_CPUID_FEATURE_ECX_VMX)
- && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR)
- && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR)
- )
+ /* AMD-V */
+ else if (ASMIsAmdCpuEx(uVendorEBX, uVendorECX, uVendorEDX))
{
- int rc = SUPR3QueryVTxSupported();
- if (RT_SUCCESS(rc))
+ if ( (fExtFeaturesEcx & X86_CPUID_AMD_FEATURE_ECX_SVM)
+ && (fFeaturesEdx & X86_CPUID_FEATURE_EDX_MSR)
+ && (fFeaturesEdx & X86_CPUID_FEATURE_EDX_FXSR)
+ && ASMIsValidExtRange(uExtMaxId)
+ )
+ {
m->fVTSupported = true;
+
+ /* Query AMD features. */
+ if (uExtMaxId >= 0x8000000a)
+ {
+ uint32_t fSVMFeaturesEdx;
+ ASMCpuId(0x8000000a, &uDummy, &uDummy, &uDummy, &fSVMFeaturesEdx);
+ if (fSVMFeaturesEdx & AMD_CPUID_SVM_FEATURE_EDX_NESTED_PAGING)
+ m->fNestedPagingSupported = true;
+ }
+ }
}
}
}
-#if 0 /* needs testing */
+ /* Check with SUPDrv if VT-x and AMD-V are really supported (may fail). */
if (m->fVTSupported)
{
- uint32_t u32Caps = 0;
-
- int rc = SUPR3QueryVTCaps(&u32Caps);
+ int rc = SUPR3InitEx(false /*fUnrestricted*/, NULL);
if (RT_SUCCESS(rc))
{
- if (u32Caps & SUPVTCAPS_NESTED_PAGING)
- m->fNestedPagingSupported = true;
+ uint32_t fVTCaps;
+ rc = SUPR3QueryVTCaps(&fVTCaps);
+ if (RT_SUCCESS(rc))
+ {
+ Assert(fVTCaps & (SUPVTCAPS_AMD_V | SUPVTCAPS_VT_X));
+ if (fVTCaps & SUPVTCAPS_NESTED_PAGING)
+ m->fNestedPagingSupported = true;
+ else
+ Assert(m->fNestedPagingSupported == false);
+ }
+ else
+ {
+ LogRel(("SUPR0QueryVTCaps -> %Rrc\n", rc));
+ m->fVTSupported = m->fNestedPagingSupported = false;
+ }
}
- /* else @todo; report BIOS trouble in some way. */
+ else
+ m->fRecheckVTSupported = true; /* Try again later when the driver is loaded. */
}
-#endif
-
- /* Test for 3D hardware acceleration support */
- m->f3DAccelerationSupported = false;
#ifdef VBOX_WITH_CROGL
- m->f3DAccelerationSupported = VBoxOglIs3DAccelerationSupported();
-#endif /* VBOX_WITH_CROGL */
+ /* Test for 3D hardware acceleration support later when (if ever) need. */
+ m->f3DAccelerationSupported = -1;
+#else
+ m->f3DAccelerationSupported = false;
+#endif
#if defined (RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
/* Extract the list of configured host-only interfaces */
@@ -547,7 +571,7 @@ static int vboxNetWinAddComponent(std::list< ComObjPtr<HostNetworkInterface> > *
HRESULT hr;
int rc = VERR_GENERAL_FAILURE;
- hr = pncc->GetDisplayName( &lpszName );
+ hr = pncc->GetDisplayName(&lpszName);
Assert(hr == S_OK);
if (hr == S_OK)
{
@@ -640,10 +664,10 @@ STDMETHODIMP Host::COMGETTER(NetworkInterfaces)(ComSafeArrayOut(IHostNetworkInte
INetCfgBindingInterface *pBi;
/* we are using the INetCfg API for getting the list of miniports */
- hr = VBoxNetCfgWinQueryINetCfg( FALSE,
- VBOX_APP_NAME,
- &pNc,
- &lpszApp );
+ hr = VBoxNetCfgWinQueryINetCfg(FALSE,
+ VBOX_APP_NAME,
+ &pNc,
+ &lpszApp);
Assert(hr == S_OK);
if (hr == S_OK)
{
@@ -666,24 +690,24 @@ STDMETHODIMP Host::COMGETTER(NetworkInterfaces)(ComSafeArrayOut(IHostNetworkInte
{
hr = VBoxNetCfgWinGetBindingPathEnum(pTcpIpNcc, EBP_BELOW, &pEnumBp);
Assert(hr == S_OK);
- if ( hr == S_OK )
+ if (hr == S_OK)
{
hr = VBoxNetCfgWinGetFirstBindingPath(pEnumBp, &pBp);
Assert(hr == S_OK || hr == S_FALSE);
- while( hr == S_OK )
+ while (hr == S_OK)
{
/* S_OK == enabled, S_FALSE == disabled */
if (pBp->IsEnabled() == S_OK)
{
hr = VBoxNetCfgWinGetBindingInterfaceEnum(pBp, &pEnumBi);
Assert(hr == S_OK);
- if ( hr == S_OK )
+ if (hr == S_OK)
{
hr = VBoxNetCfgWinGetFirstBindingInterface(pEnumBi, &pBi);
Assert(hr == S_OK);
- while(hr == S_OK)
+ while (hr == S_OK)
{
- hr = pBi->GetLowerComponent( &pMpNcc );
+ hr = pBi->GetLowerComponent(&pMpNcc);
Assert(hr == S_OK);
if (hr == S_OK)
{
@@ -697,7 +721,7 @@ STDMETHODIMP Host::COMGETTER(NetworkInterfaces)(ComSafeArrayOut(IHostNetworkInte
vboxNetWinAddComponent(&list, pMpNcc);
}
}
- VBoxNetCfgWinReleaseRef( pMpNcc );
+ VBoxNetCfgWinReleaseRef(pMpNcc);
}
VBoxNetCfgWinReleaseRef(pBi);
@@ -795,6 +819,54 @@ STDMETHODIMP Host::COMGETTER(USBDevices)(ComSafeArrayOut(IHostUSBDevice*, aUSBDe
#endif
}
+
+/**
+ * This method return the list of registered name servers
+ */
+STDMETHODIMP Host::COMGETTER(NameServers)(ComSafeArrayOut(BSTR, aNameServers))
+{
+ CheckComArgOutSafeArrayPointerValid(aNameServers);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ return m->hostDnsMonitorProxy.GetNameServers(ComSafeArrayOutArg(aNameServers));
+}
+
+
+/**
+ * This method returns the domain name of the host
+ */
+STDMETHODIMP Host::COMGETTER(DomainName)(BSTR *aDomainName)
+{
+ /* XXX: note here should be synchronization with thread polling state
+ * changes in name resoving system on host */
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ return m->hostDnsMonitorProxy.GetDomainName(aDomainName);
+}
+
+
+/**
+ * This method returns the search string.
+ */
+STDMETHODIMP Host::COMGETTER(SearchStrings)(ComSafeArrayOut(BSTR, aSearchStrings))
+{
+ CheckComArgOutSafeArrayPointerValid(aSearchStrings);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ return m->hostDnsMonitorProxy.GetSearchStrings(ComSafeArrayOutArg(aSearchStrings));
+}
+
+
STDMETHODIMP Host::COMGETTER(USBDeviceFilters)(ComSafeArrayOut(IHostUSBDeviceFilter*, aUSBDeviceFilters))
{
#ifdef VBOX_WITH_USB
@@ -865,7 +937,23 @@ STDMETHODIMP Host::COMGETTER(ProcessorCoreCount)(ULONG *aCount)
CheckComArgOutPointerValid(aCount);
// no locking required
- return E_NOTIMPL;
+ *aCount = RTMpGetPresentCoreCount();
+ return S_OK;
+}
+
+/**
+ * Returns the number of installed physical processor cores.
+ *
+ * @returns COM status code
+ * @param count address of result variable
+ */
+STDMETHODIMP Host::COMGETTER(ProcessorOnlineCoreCount)(ULONG *aCount)
+{
+ CheckComArgOutPointerValid(aCount);
+ // no locking required
+
+ *aCount = RTMpGetOnlineCoreCount();
+ return S_OK;
}
/**
@@ -913,34 +1001,82 @@ STDMETHODIMP Host::GetProcessorDescription(ULONG aCpuId, BSTR *aDescription)
*/
STDMETHODIMP Host::GetProcessorFeature(ProcessorFeature_T aFeature, BOOL *aSupported)
{
+ /* Validate input. */
CheckComArgOutPointerValid(aSupported);
- AutoCaller autoCaller(this);
- if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
- AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
switch (aFeature)
{
case ProcessorFeature_HWVirtEx:
- *aSupported = m->fVTSupported;
- break;
-
case ProcessorFeature_PAE:
- *aSupported = m->fPAESupported;
- break;
-
case ProcessorFeature_LongMode:
- *aSupported = m->fLongModeSupported;
- break;
-
case ProcessorFeature_NestedPaging:
- *aSupported = m->fNestedPagingSupported;
break;
-
default:
- ReturnComNotImplemented();
+ return setError(E_INVALIDARG, tr("The aFeature value %d (%#x) is out of range."), (int)aFeature, (int)aFeature);
}
- return S_OK;
+
+ /* Do the job. */
+ AutoCaller autoCaller(this);
+ HRESULT hrc = autoCaller.rc();
+ if (SUCCEEDED(hrc))
+ {
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if ( m->fRecheckVTSupported
+ && ( aFeature == ProcessorFeature_HWVirtEx
+ || aFeature == ProcessorFeature_NestedPaging)
+ )
+ {
+ alock.release();
+
+ /* Perhaps the driver is available now... */
+ int rc = SUPR3InitEx(false /*fUnrestricted*/, NULL);
+ if (RT_SUCCESS(rc))
+ {
+ uint32_t fVTCaps;
+ rc = SUPR3QueryVTCaps(&fVTCaps);
+
+ AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
+ if (RT_SUCCESS(rc))
+ {
+ Assert(fVTCaps & (SUPVTCAPS_AMD_V | SUPVTCAPS_VT_X));
+ if (fVTCaps & SUPVTCAPS_NESTED_PAGING)
+ m->fNestedPagingSupported = true;
+ else
+ Assert(m->fNestedPagingSupported == false);
+ }
+ else
+ {
+ LogRel(("SUPR0QueryVTCaps -> %Rrc\n", rc));
+ m->fVTSupported = m->fNestedPagingSupported = true;
+ }
+ }
+
+ alock.acquire();
+ }
+
+ switch (aFeature)
+ {
+ case ProcessorFeature_HWVirtEx:
+ *aSupported = m->fVTSupported;
+ break;
+
+ case ProcessorFeature_PAE:
+ *aSupported = m->fPAESupported;
+ break;
+
+ case ProcessorFeature_LongMode:
+ *aSupported = m->fLongModeSupported;
+ break;
+
+ case ProcessorFeature_NestedPaging:
+ *aSupported = m->fNestedPagingSupported;
+ break;
+
+ default:
+ AssertFailed();
+ }
+ }
+ return hrc;
}
/**
@@ -992,15 +1128,12 @@ STDMETHODIMP Host::COMGETTER(MemorySize)(ULONG *aSize)
CheckComArgOutPointerValid(aSize);
// no locking required
- /* @todo This is an ugly hack. There must be a function in IPRT for that. */
- pm::CollectorHAL *hal = pm::createHAL();
- if (!hal)
+ uint64_t cb;
+ int rc = RTSystemQueryTotalRam(&cb);
+ if (RT_FAILURE(rc))
return E_FAIL;
- ULONG tmp;
- int rc = hal->getHostMemoryUsage(aSize, &tmp, &tmp);
- *aSize /= 1024;
- delete hal;
- return rc;
+ *aSize = (ULONG)(cb / _1M);
+ return S_OK;
}
/**
@@ -1014,15 +1147,12 @@ STDMETHODIMP Host::COMGETTER(MemoryAvailable)(ULONG *aAvailable)
CheckComArgOutPointerValid(aAvailable);
// no locking required
- /* @todo This is an ugly hack. There must be a function in IPRT for that. */
- pm::CollectorHAL *hal = pm::createHAL();
- if (!hal)
+ uint64_t cb;
+ int rc = RTSystemQueryAvailableRam(&cb);
+ if (RT_FAILURE(rc))
return E_FAIL;
- ULONG tmp;
- int rc = hal->getHostMemoryUsage(&tmp, &tmp, aAvailable);
- *aAvailable /= 1024;
- delete hal;
- return rc;
+ *aAvailable = (ULONG)(cb / _1M);
+ return S_OK;
}
/**
@@ -1101,17 +1231,33 @@ STDMETHODIMP Host::COMGETTER(Acceleration3DAvailable)(BOOL *aSupported)
{
CheckComArgOutPointerValid(aSupported);
AutoCaller autoCaller(this);
- if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
- AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+ HRESULT hrc = autoCaller.rc();
+ if (SUCCEEDED(hrc))
+ {
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+ if (m->f3DAccelerationSupported != -1)
+ *aSupported = m->f3DAccelerationSupported;
+ else
+ {
+ alock.release();
+#ifdef VBOX_WITH_CROGL
+ bool fSupported = VBoxOglIs3DAccelerationSupported();
+#else
+ bool fSupported = false; /* shoudn't get here, but just in case. */
+#endif
+ AutoWriteLock alock2(this COMMA_LOCKVAL_SRC_POS);
+ m->f3DAccelerationSupported = fSupported;
+ alock2.release();
- *aSupported = m->f3DAccelerationSupported;
+ *aSupported = fSupported;
+ }
+ }
#ifdef DEBUG_misha
AssertMsgFailed(("should not be here any more!\n"));
#endif
- return S_OK;
+ return hrc;
}
STDMETHODIMP Host::CreateHostOnlyNetworkInterface(IHostNetworkInterface **aHostNetworkInterface,
@@ -1433,7 +1579,7 @@ STDMETHODIMP Host::FindHostNetworkInterfaceById(IN_BSTR id, IHostNetworkInterfac
#ifndef VBOX_WITH_HOSTNETIF_API
return E_NOTIMPL;
#else
- if (Guid(id).isEmpty())
+ if (!Guid(id).isValid())
return E_INVALIDARG;
if (!networkInterface)
return E_POINTER;
@@ -1537,7 +1683,7 @@ STDMETHODIMP Host::FindUSBDeviceById(IN_BSTR aId,
IHostUSBDevice **aDevice)
{
#ifdef VBOX_WITH_USB
- CheckComArgExpr(aId, Guid (aId).isEmpty() == false);
+ CheckComArgExpr(aId, Guid (aId).isValid());
CheckComArgOutPointerValid(aDevice);
*aDevice = NULL;
@@ -1578,6 +1724,34 @@ STDMETHODIMP Host::GenerateMACAddress(BSTR *aAddress)
return S_OK;
}
+/**
+ * Returns a list of host video capture devices (webcams, etc).
+ *
+ * @returns COM status code
+ * @param aVideoInputDevices Array of interface pointers to be filled.
+ */
+STDMETHODIMP Host::COMGETTER(VideoInputDevices)(ComSafeArrayOut(IHostVideoInputDevice*, aVideoInputDevices))
+{
+ if (ComSafeArrayOutIsNull(aVideoInputDevices))
+ return E_POINTER;
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+ HostVideoInputDeviceList list;
+
+ HRESULT hr = HostVideoInputDevice::queryHostDevices(m->pParent, &list);
+
+ if (SUCCEEDED(hr))
+ {
+ SafeIfaceArray<IHostVideoInputDevice> devices(list);
+ devices.detachTo(ComSafeArrayOutArg(aVideoInputDevices));
+ }
+
+ return hr;
+}
+
// public methods only for internal purposes
////////////////////////////////////////////////////////////////////////////////
@@ -1868,7 +2042,7 @@ HRESULT Host::findHostDriveByNameOrId(DeviceType_T mediumType,
AutoWriteLock wlock(m->pParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
Guid uuid(strNameOrId);
- if (!uuid.isEmpty())
+ if (uuid.isValid() && !uuid.isZero())
return findHostDriveById(mediumType, uuid, true /* fRefresh */, pMedium);
// string is not a syntactically valid UUID: try a name then
@@ -2228,7 +2402,7 @@ static int solarisWalkDeviceNodeForDVD(di_node_t Node, void *pvArg)
{
char *pszSlice = solarisGetSliceFromPath(pszDevLinkPath);
if ( pszSlice && !strcmp(pszSlice, "s2")
- && !strncmp(pszDevLinkPath, "/dev/rdsk", sizeof("/dev/rdsk") - 1)) /* We want only raw disks */
+ && !strncmp(pszDevLinkPath, RT_STR_TUPLE("/dev/rdsk"))) /* We want only raw disks */
{
/*
* We've got a fully qualified DVD drive. Add it to the list.
@@ -2680,9 +2854,9 @@ void Host::parseMountTable(char *mountTable, std::list< ComObjPtr<Medium> > &lis
{
// skip devices we are not interested in
if ((*mountName && mountName[0] == '/') && // skip 'fake' devices (like -hosts, proc, fd, swap)
- (*mountFSType && (strncmp(mountFSType, "devfs", 5) != 0 && // skip devfs (i.e. /devices)
- strncmp(mountFSType, "dev", 3) != 0 && // skip dev (i.e. /dev)
- strncmp(mountFSType, "lofs", 4) != 0))) // skip loop-back file-system (lofs)
+ (*mountFSType && (strncmp(mountFSType, RT_STR_TUPLE("devfs")) != 0 && // skip devfs (i.e. /devices)
+ strncmp(mountFSType, RT_STR_TUPLE("dev")) != 0 && // skip dev (i.e. /dev)
+ strncmp(mountFSType, RT_STR_TUPLE("lofs")) != 0))) // skip loop-back file-system (lofs)
{
char *rawDevName = getfullrawname((char *)mountName);
if (validateDevice(rawDevName, true))
@@ -2834,7 +3008,9 @@ HRESULT Host::updateNetIfList()
/* Make a copy as the original may be partially destroyed later. */
listCopy = list;
HostNetworkInterfaceList::iterator itOld, itNew;
+# ifdef VBOX_WITH_RESOURCE_USAGE_API
PerformanceCollector *aCollector = m->pParent->performanceCollector();
+# endif
for (itOld = m->llNetIfs.begin(); itOld != m->llNetIfs.end(); ++itOld)
{
bool fGone = true;
@@ -2852,7 +3028,11 @@ HRESULT Host::updateNetIfList()
}
}
if (fGone)
+ {
+# ifdef VBOX_WITH_RESOURCE_USAGE_API
(*itOld)->unregisterMetrics(aCollector, this);
+# endif
+ }
}
/*
* Need to set the references to VirtualBox object in all interface objects
@@ -2872,7 +3052,11 @@ HRESULT Host::updateNetIfList()
LogRel(("Host::updateNetIfList: failed to get interface type for %ls\n", n.raw()));
}
else if (t == HostNetworkInterfaceType_Bridged)
+ {
+# ifdef VBOX_WITH_RESOURCE_USAGE_API
(*itNew)->registerMetrics(aCollector, this);
+# endif
+ }
}
m->llNetIfs = list;
return S_OK;
@@ -2928,17 +3112,17 @@ void Host::registerDiskMetrics(PerformanceCollector *aCollector)
new pm::AggregateMax()));
/* For now we are concerned with the root file system only. */
- pm::DiskList disks;
- int rc = pm::getDiskListByFs("/", disks);
- if (RT_FAILURE(rc) || disks.empty())
+ pm::DiskList disksUsage, disksLoad;
+ int rc = hal->getDiskListByFs("/", disksUsage, disksLoad);
+ if (RT_FAILURE(rc))
return;
pm::DiskList::iterator it;
- for (it = disks.begin(); it != disks.end(); ++it)
+ for (it = disksLoad.begin(); it != disksLoad.end(); ++it)
{
- Utf8StrFmt strName("Disk/%s/Load", it->c_str());
- pm::SubMetric *fsLoadUtil = new pm::SubMetric(strName + "/Util",
+ Utf8StrFmt strName("Disk/%s", it->c_str());
+ pm::SubMetric *fsLoadUtil = new pm::SubMetric(strName + "/Load/Util",
"Percentage of time disk was busy serving I/O requests.");
- pm::BaseMetric *fsLoad = new pm::HostDiskLoadRaw(hal, this, strName,
+ pm::BaseMetric *fsLoad = new pm::HostDiskLoadRaw(hal, this, strName + "/Load",
*it, fsLoadUtil);
aCollector->registerBaseMetric (fsLoad);
@@ -2950,6 +3134,23 @@ void Host::registerDiskMetrics(PerformanceCollector *aCollector)
aCollector->registerMetric(new pm::Metric(fsLoad, fsLoadUtil,
new pm::AggregateMax()));
}
+ for (it = disksUsage.begin(); it != disksUsage.end(); ++it)
+ {
+ Utf8StrFmt strName("Disk/%s", it->c_str());
+ pm::SubMetric *fsUsageTotal = new pm::SubMetric(strName + "/Usage/Total",
+ "Disk size.");
+ pm::BaseMetric *fsUsage = new pm::HostDiskUsage(hal, this, strName + "/Usage",
+ *it, fsUsageTotal);
+ aCollector->registerBaseMetric (fsUsage);
+
+ aCollector->registerMetric(new pm::Metric(fsUsage, fsUsageTotal, 0));
+ aCollector->registerMetric(new pm::Metric(fsUsage, fsUsageTotal,
+ new pm::AggregateAvg()));
+ aCollector->registerMetric(new pm::Metric(fsUsage, fsUsageTotal,
+ new pm::AggregateMin()));
+ aCollector->registerMetric(new pm::Metric(fsUsage, fsUsageTotal,
+ new pm::AggregateMax()));
+ }
}
void Host::registerMetrics(PerformanceCollector *aCollector)
@@ -3094,6 +3295,8 @@ void Host::unregisterMetrics (PerformanceCollector *aCollector)
aCollector->unregisterBaseMetricsFor(this);
}
+#endif /* VBOX_WITH_RESOURCE_USAGE_API */
+
/* static */
void Host::generateMACAddress(Utf8Str &mac)
@@ -3109,6 +3312,4 @@ void Host::generateMACAddress(Utf8Str &mac)
guid.raw()->au8[0], guid.raw()->au8[1], guid.raw()->au8[2]);
}
-#endif /* VBOX_WITH_RESOURCE_USAGE_API */
-
/* vi: set tabstop=4 shiftwidth=4 expandtab: */
diff --git a/src/VBox/Main/src-server/HostNetworkInterfaceImpl.cpp b/src/VBox/Main/src-server/HostNetworkInterfaceImpl.cpp
index 1eeef5b5..58c5fd3b 100644
--- a/src/VBox/Main/src-server/HostNetworkInterfaceImpl.cpp
+++ b/src/VBox/Main/src-server/HostNetworkInterfaceImpl.cpp
@@ -6,7 +6,7 @@
*/
/*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -21,8 +21,10 @@
#include "AutoCaller.h"
#include "Logging.h"
#include "netif.h"
-#include "Performance.h"
-#include "PerformanceImpl.h"
+#ifdef VBOX_WITH_RESOURCE_USAGE_API
+# include "Performance.h"
+# include "PerformanceImpl.h"
+#endif
#include <iprt/cpp/utils.h>
@@ -69,7 +71,7 @@ HRESULT HostNetworkInterface::init(Bstr aInterfaceName, Bstr aShortName, Guid aG
aInterfaceName.raw(), aGuid.toString().c_str()));
ComAssertRet(!aInterfaceName.isEmpty(), E_INVALIDARG);
- ComAssertRet(!aGuid.isEmpty(), E_INVALIDARG);
+ ComAssertRet(aGuid.isValid(), E_INVALIDARG);
/* Enclose the state transition NotReady->InInit->Ready */
AutoInitSpan autoInitSpan(this);
@@ -77,6 +79,7 @@ HRESULT HostNetworkInterface::init(Bstr aInterfaceName, Bstr aShortName, Guid aG
unconst(mInterfaceName) = aInterfaceName;
unconst(mNetworkName) = composeNetworkName(aShortName);
+ unconst(mShortName) = aShortName;
unconst(mGuid) = aGuid;
mIfType = ifType;
@@ -86,22 +89,36 @@ HRESULT HostNetworkInterface::init(Bstr aInterfaceName, Bstr aShortName, Guid aG
return S_OK;
}
+#ifdef VBOX_WITH_RESOURCE_USAGE_API
+
void HostNetworkInterface::registerMetrics(PerformanceCollector *aCollector, ComPtr<IUnknown> objptr)
{
LogFlowThisFunc(("mShortName={%ls}, mInterfaceName={%ls}, mGuid={%s}, mSpeedMbits=%u\n",
mShortName.raw(), mInterfaceName.raw(), mGuid.toString().c_str(), m.speedMbits));
pm::CollectorHAL *hal = aCollector->getHAL();
/* Create sub metrics */
- Utf8StrFmt strName("Net/%ls/Load", mShortName.raw());
- pm::SubMetric *networkLoadRx = new pm::SubMetric(strName + "/Rx",
+ Utf8StrFmt strName("Net/%ls", mShortName.raw());
+ pm::SubMetric *networkLoadRx = new pm::SubMetric(strName + "/Load/Rx",
"Percentage of network interface receive bandwidth used.");
- pm::SubMetric *networkLoadTx = new pm::SubMetric(strName + "/Tx",
+ pm::SubMetric *networkLoadTx = new pm::SubMetric(strName + "/Load/Tx",
"Percentage of network interface transmit bandwidth used.");
+ pm::SubMetric *networkLinkSpeed = new pm::SubMetric(strName + "/LinkSpeed",
+ "Physical link speed.");
/* Create and register base metrics */
- pm::BaseMetric *networkLoad = new pm::HostNetworkLoadRaw(hal, objptr, strName, Utf8Str(mShortName), Utf8Str(mInterfaceName), m.speedMbits, networkLoadRx, networkLoadTx);
+ pm::BaseMetric *networkSpeed = new pm::HostNetworkSpeed(hal, objptr, strName + "/LinkSpeed", Utf8Str(mShortName), Utf8Str(mInterfaceName), m.speedMbits, networkLinkSpeed);
+ aCollector->registerBaseMetric(networkSpeed);
+ pm::BaseMetric *networkLoad = new pm::HostNetworkLoadRaw(hal, objptr, strName + "/Load", Utf8Str(mShortName), Utf8Str(mInterfaceName), m.speedMbits, networkLoadRx, networkLoadTx);
aCollector->registerBaseMetric(networkLoad);
+ aCollector->registerMetric(new pm::Metric(networkSpeed, networkLinkSpeed, 0));
+ aCollector->registerMetric(new pm::Metric(networkSpeed, networkLinkSpeed,
+ new pm::AggregateAvg()));
+ aCollector->registerMetric(new pm::Metric(networkSpeed, networkLinkSpeed,
+ new pm::AggregateMin()));
+ aCollector->registerMetric(new pm::Metric(networkSpeed, networkLinkSpeed,
+ new pm::AggregateMax()));
+
aCollector->registerMetric(new pm::Metric(networkLoad, networkLoadRx, 0));
aCollector->registerMetric(new pm::Metric(networkLoad, networkLoadRx,
new pm::AggregateAvg()));
@@ -123,11 +140,13 @@ void HostNetworkInterface::unregisterMetrics(PerformanceCollector *aCollector, C
{
LogFlowThisFunc(("mShortName={%ls}, mInterfaceName={%ls}, mGuid={%s}\n",
mShortName.raw(), mInterfaceName.raw(), mGuid.toString().c_str()));
- Utf8StrFmt name("Net/%ls/Load", mShortName.raw());
+ Utf8StrFmt name("Net/%ls", mShortName.raw());
aCollector->unregisterMetricsFor(objptr, name + "/*");
aCollector->unregisterBaseMetricsFor(objptr, name);
}
+#endif /* VBOX_WITH_RESOURCE_USAGE_API */
+
#ifdef VBOX_WITH_HOSTNETIF_API
HRESULT HostNetworkInterface::updateConfig()
@@ -172,7 +191,7 @@ HRESULT HostNetworkInterface::init(Bstr aInterfaceName, HostNetworkInterfaceType
// aInterfaceName.raw(), aGuid.toString().raw()));
// ComAssertRet(aInterfaceName, E_INVALIDARG);
-// ComAssertRet(!aGuid.isEmpty(), E_INVALIDARG);
+// ComAssertRet(aGuid.isValid(), E_INVALIDARG);
ComAssertRet(pIf, E_INVALIDARG);
/* Enclose the state transition NotReady->InInit->Ready */
@@ -237,6 +256,24 @@ STDMETHODIMP HostNetworkInterface::COMGETTER(Name)(BSTR *aInterfaceName)
}
/**
+ * Returns the short name of the host network interface.
+ *
+ * @returns COM status code
+ * @param aShortName address of result pointer
+ */
+STDMETHODIMP HostNetworkInterface::COMGETTER(ShortName)(BSTR *aShortName)
+{
+ CheckComArgOutPointerValid(aShortName);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ mShortName.cloneTo(aShortName);
+
+ return S_OK;
+}
+
+/**
* Returns the GUID of the host network interface.
*
* @returns COM status code
diff --git a/src/VBox/Main/src-server/HostPower.cpp b/src/VBox/Main/src-server/HostPower.cpp
index 830729a0..3146a7ae 100644
--- a/src/VBox/Main/src-server/HostPower.cpp
+++ b/src/VBox/Main/src-server/HostPower.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -26,10 +26,11 @@
#include <VBox/com/ptr.h>
#include "VirtualBoxImpl.h"
+#include "MachineImpl.h"
#include <iprt/mem.h>
-HostPowerService::HostPowerService (VirtualBox *aVirtualBox)
+HostPowerService::HostPowerService(VirtualBox *aVirtualBox)
{
Assert(aVirtualBox != NULL);
mVirtualBox = aVirtualBox;
@@ -39,18 +40,18 @@ HostPowerService::~HostPowerService()
{
}
-void HostPowerService::notify(HostPowerEvent aEvent)
+void HostPowerService::notify(Reason_T aReason)
{
SessionMachinesList machines;
VirtualBox::InternalControlList controls;
HRESULT rc = S_OK;
- switch (aEvent)
+ switch (aReason)
{
- case HostPowerEvent_Suspend:
+ case Reason_HostSuspend:
{
- LogFunc (("SUSPEND\n"));
+ LogFunc(("HOST SUSPEND\n"));
#ifdef VBOX_WITH_RESOURCE_USAGE_API
/* Suspend performance sampling to avoid unnecessary callbacks due to jumps in time. */
@@ -68,49 +69,41 @@ void HostPowerService::notify(HostPowerEvent aEvent)
{
ComPtr<IInternalSessionControl> pControl = *it;
- /* get the remote console */
- ComPtr<IConsole> console;
- rc = pControl->GetRemoteConsole(console.asOutParam());
- /* the VM could have been powered down and closed or whatever */
- if (FAILED(rc))
- continue;
-
- /* note that Pause() will simply return a failure if the VM is
- * in an inappropriate state */
- rc = console->Pause();
+ /* PauseWithReason() will simply return a failure if
+ * the VM is in an inappropriate state */
+ rc = pControl->PauseWithReason(Reason_HostSuspend);
if (FAILED(rc))
continue;
/* save the control to un-pause the VM later */
- mConsoles.push_back(console);
+ mSessionControls.push_back(pControl);
}
- LogFunc (("Suspended %d VMs\n", mConsoles.size()));
-
+ LogRel(("Host suspending: Paused %d VMs\n", mSessionControls.size()));
break;
}
- case HostPowerEvent_Resume:
+ case Reason_HostResume:
{
- LogFunc (("RESUME\n"));
+ LogFunc(("HOST RESUME\n"));
size_t resumed = 0;
/* go through VMs we paused on Suspend */
- for (size_t i = 0; i < mConsoles.size(); ++i)
+ for (size_t i = 0; i < mSessionControls.size(); ++i)
{
/* note that Resume() will simply return a failure if the VM is
* in an inappropriate state (it will also fail if the VM has
* been somehow closed by this time already so that the
* console reference we have is dead) */
- rc = mConsoles[i]->Resume();
+ rc = mSessionControls[i]->ResumeWithReason(Reason_HostResume);
if (FAILED(rc))
continue;
- ++ resumed;
+ ++resumed;
}
- LogFunc (("Resumed %d VMs\n", resumed));
+ LogRel(("Host resumed: Resumed %d VMs\n", resumed));
#ifdef VBOX_WITH_RESOURCE_USAGE_API
/* Resume the performance sampling. */
@@ -120,60 +113,87 @@ void HostPowerService::notify(HostPowerEvent aEvent)
perfcollector->resumeSampling();
#endif
- mConsoles.clear();
-
+ mSessionControls.clear();
break;
}
- case HostPowerEvent_BatteryLow:
+ case Reason_HostBatteryLow:
{
- LogFunc (("BATTERY LOW\n"));
+ LogFunc(("BATTERY LOW\n"));
- mVirtualBox->getOpenedMachines(machines, &controls);
+ Bstr value;
+ rc = mVirtualBox->GetExtraData(Bstr("VBoxInternal2/SavestateOnBatteryLow").raw(),
+ value.asOutParam());
+ int fGlobal = 0;
+ if (SUCCEEDED(rc) && !value.isEmpty())
+ {
+ if (value != "0")
+ fGlobal = 1;
+ else if (value == "0")
+ fGlobal = -1;
+ }
+ mVirtualBox->getOpenedMachines(machines, &controls);
size_t saved = 0;
/* save running VMs */
+ SessionMachinesList::const_iterator it2 = machines.begin();
for (VirtualBox::InternalControlList::const_iterator it = controls.begin();
- it != controls.end();
- ++it)
+ it != controls.end() && it2 != machines.end();
+ ++it, ++it2)
{
- ComPtr<IInternalSessionControl> pControl = *it;
- /* get the remote console */
- ComPtr<IConsole> console;
- rc = pControl->GetRemoteConsole (console.asOutParam());
- /* the VM could have been powered down and closed or whatever */
- if (FAILED(rc))
- continue;
-
- ComPtr<IProgress> progress;
-
- /* note that SaveState() will simply return a failure if the VM
- * is in an inappropriate state */
- rc = console->SaveState (progress.asOutParam());
- if (FAILED(rc))
- continue;
-
- /* Wait until the operation has been completed. */
- rc = progress->WaitForCompletion(-1);
- if (SUCCEEDED(rc))
+ ComPtr<SessionMachine> pMachine = *it2;
+ rc = pMachine->GetExtraData(Bstr("VBoxInternal2/SavestateOnBatteryLow").raw(),
+ value.asOutParam());
+ int fPerVM = 0;
+ if (SUCCEEDED(rc) && !value.isEmpty())
{
- LONG iRc;
- progress->COMGETTER(ResultCode)(&iRc);
- rc = iRc;
+ /* per-VM overrides global */
+ if (value != "0")
+ fPerVM = 2;
+ else if (value == "0")
+ fPerVM = -2;
}
- AssertMsg (SUCCEEDED(rc), ("SaveState WaitForCompletion "
- "failed with %Rhrc (%#08X)\n", rc, rc));
-
- if (SUCCEEDED(rc))
- ++ saved;
+ /* default is true */
+ if (fGlobal + fPerVM >= 0)
+ {
+ ComPtr<IInternalSessionControl> pControl = *it;
+ ComPtr<IProgress> progress;
+
+ /* note that SaveStateWithReason() will simply return a failure
+ * if the VM is in an inappropriate state */
+ rc = pControl->SaveStateWithReason(Reason_HostBatteryLow, progress.asOutParam());
+ if (FAILED(rc))
+ {
+ LogRel(("SaveState '%s' failed with %Rhrc\n", pMachine->getName().c_str(), rc));
+ continue;
+ }
+
+ /* Wait until the operation has been completed. */
+ rc = progress->WaitForCompletion(-1);
+ if (SUCCEEDED(rc))
+ {
+ LONG iRc;
+ progress->COMGETTER(ResultCode)(&iRc);
+ rc = iRc;
+ }
+
+ AssertMsg(SUCCEEDED(rc), ("SaveState WaitForCompletion failed with %Rhrc (%#08X)\n", rc, rc));
+
+ if (SUCCEEDED(rc))
+ {
+ LogRel(("SaveState '%s' succeeded\n", pMachine->getName().c_str()));
+ ++saved;
+ }
+ }
}
-
- LogFunc (("Saved %d VMs\n", saved));
-
+ LogRel(("Battery Low: saved %d VMs\n", saved));
break;
}
+
+ default:
+ /* nothing */;
}
}
/* vi: set tabstop=4 shiftwidth=4 expandtab: */
diff --git a/src/VBox/Main/src-server/HostVideoInputDeviceImpl.cpp b/src/VBox/Main/src-server/HostVideoInputDeviceImpl.cpp
new file mode 100644
index 00000000..1e7a53d2
--- /dev/null
+++ b/src/VBox/Main/src-server/HostVideoInputDeviceImpl.cpp
@@ -0,0 +1,235 @@
+/* $Id: HostVideoInputDeviceImpl.cpp $ */
+/** @file
+ *
+ * Host video capture device implementation.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "HostVideoInputDeviceImpl.h"
+#include "Logging.h"
+#include "VirtualBoxImpl.h"
+#ifdef VBOX_WITH_EXTPACK
+# include "ExtPackManagerImpl.h"
+#endif
+
+#include <iprt/ldr.h>
+#include <iprt/path.h>
+
+#include <VBox/sup.h>
+
+/*
+ * HostVideoInputDevice implementation.
+ */
+DEFINE_EMPTY_CTOR_DTOR(HostVideoInputDevice)
+
+HRESULT HostVideoInputDevice::FinalConstruct()
+{
+ return BaseFinalConstruct();
+}
+
+void HostVideoInputDevice::FinalRelease()
+{
+ uninit();
+
+ BaseFinalRelease();
+}
+
+/*
+ * Initializes the instance.
+ */
+HRESULT HostVideoInputDevice::init(const com::Utf8Str &name, const com::Utf8Str &path, const com::Utf8Str &alias)
+{
+ LogFlowThisFunc(("\n"));
+
+ /* Enclose the state transition NotReady->InInit->Ready */
+ AutoInitSpan autoInitSpan(this);
+ AssertReturn(autoInitSpan.isOk(), E_FAIL);
+
+ m.name = name;
+ m.path = path;
+ m.alias = alias;
+
+ /* Confirm a successful initialization */
+ autoInitSpan.setSucceeded();
+
+ return S_OK;
+}
+
+/*
+ * Uninitializes the instance.
+ * Called either from FinalRelease() or by the parent when it gets destroyed.
+ */
+void HostVideoInputDevice::uninit()
+{
+ LogFlowThisFunc(("\n"));
+
+ m.name.setNull();
+ m.path.setNull();
+ m.alias.setNull();
+
+ /* Enclose the state transition Ready->InUninit->NotReady */
+ AutoUninitSpan autoUninitSpan(this);
+ if (autoUninitSpan.uninitDone())
+ return;
+}
+
+static HRESULT hostVideoInputDeviceAdd(HostVideoInputDeviceList *pList,
+ const com::Utf8Str &name,
+ const com::Utf8Str &path,
+ const com::Utf8Str &alias)
+{
+ ComObjPtr<HostVideoInputDevice> obj;
+ HRESULT hr = obj.createObject();
+ if (SUCCEEDED(hr))
+ {
+ hr = obj->init(name, path, alias);
+ if (SUCCEEDED(hr))
+ pList->push_back(obj);
+ }
+ return hr;
+}
+
+static DECLCALLBACK(int) hostWebcamAdd(void *pvUser,
+ const char *pszName,
+ const char *pszPath,
+ const char *pszAlias,
+ uint64_t *pu64Result)
+{
+ HostVideoInputDeviceList *pList = (HostVideoInputDeviceList *)pvUser;
+ HRESULT hr = hostVideoInputDeviceAdd(pList, pszName, pszPath, pszAlias);
+ if (FAILED(hr))
+ {
+ *pu64Result = (uint64_t)hr;
+ return VERR_NOT_SUPPORTED;
+ }
+ return VINF_SUCCESS;
+}
+
+/** @todo These typedefs must be in a header. */
+typedef DECLCALLBACK(int) FNVBOXHOSTWEBCAMADD(void *pvUser,
+ const char *pszName,
+ const char *pszPath,
+ const char *pszAlias,
+ uint64_t *pu64Result);
+typedef FNVBOXHOSTWEBCAMADD *PFNVBOXHOSTWEBCAMADD;
+
+typedef DECLCALLBACK(int) FNVBOXHOSTWEBCAMLIST(PFNVBOXHOSTWEBCAMADD pfnWebcamAdd,
+ void *pvUser,
+ uint64_t *pu64WebcamAddResult);
+typedef FNVBOXHOSTWEBCAMLIST *PFNVBOXHOSTWEBCAMLIST;
+
+static int loadHostWebcamLibrary(const char *pszPath, RTLDRMOD *phmod, PFNVBOXHOSTWEBCAMLIST *ppfn)
+{
+ int rc = VINF_SUCCESS;
+ RTLDRMOD hmod = NIL_RTLDRMOD;
+
+ RTERRINFOSTATIC ErrInfo;
+ RTErrInfoInitStatic(&ErrInfo);
+ if (RTPathHavePath(pszPath))
+ rc = SUPR3HardenedLdrLoadPlugIn(pszPath, &hmod, &ErrInfo.Core);
+ else
+ rc = VERR_INVALID_PARAMETER;
+ if (RT_SUCCESS(rc))
+ {
+ static const char *pszSymbol = "VBoxHostWebcamList";
+ rc = RTLdrGetSymbol(hmod, pszSymbol, (void **)ppfn);
+
+ if (RT_FAILURE(rc) && rc != VERR_SYMBOL_NOT_FOUND)
+ LogRel(("Resolving symbol '%s': %Rrc\n", pszSymbol, rc));
+ }
+ else
+ {
+ LogRel(("Loading the library '%s': %Rrc\n", pszPath, rc));
+ if (RTErrInfoIsSet(&ErrInfo.Core))
+ LogRel((" %s\n", ErrInfo.Core.pszMsg));
+
+ hmod = NIL_RTLDRMOD;
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ *phmod = hmod;
+ }
+ else
+ {
+ if (hmod != NIL_RTLDRMOD)
+ {
+ RTLdrClose(hmod);
+ hmod = NIL_RTLDRMOD;
+ }
+ }
+
+ return rc;
+}
+
+static const Utf8Str strExtPackPuel("Oracle VM VirtualBox Extension Pack");
+
+static HRESULT fillDeviceList(VirtualBox *pVirtualBox, HostVideoInputDeviceList *pList)
+{
+ HRESULT hr;
+ Utf8Str strLibrary;
+
+#ifdef VBOX_WITH_EXTPACK
+ ExtPackManager *pExtPackMgr = pVirtualBox->getExtPackManager();
+ hr = pExtPackMgr->getLibraryPathForExtPack("VBoxHostWebcam", &strExtPackPuel, &strLibrary);
+#else
+ hr = E_NOTIMPL;
+#endif
+
+ if (SUCCEEDED(hr))
+ {
+ PFNVBOXHOSTWEBCAMLIST pfn = NULL;
+ RTLDRMOD hmod = NIL_RTLDRMOD;
+ int rc = loadHostWebcamLibrary(strLibrary.c_str(), &hmod, &pfn);
+
+ LogRel(("Load [%s] rc %Rrc\n", strLibrary.c_str(), rc));
+
+ if (RT_SUCCESS(rc))
+ {
+ uint64_t u64Result = S_OK;
+ rc = pfn(hostWebcamAdd, pList, &u64Result);
+ Log(("VBoxHostWebcamList rc %Rrc, result 0x%08X\n", rc, u64Result));
+ if (RT_FAILURE(rc))
+ {
+ hr = (HRESULT)u64Result;
+ }
+
+ RTLdrClose(hmod);
+ hmod = NIL_RTLDRMOD;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (RT_FAILURE(rc))
+ hr = pVirtualBox->setError(VBOX_E_IPRT_ERROR,
+ "Failed to get webcam list: %Rrc", rc);
+ }
+ }
+
+ return hr;
+}
+
+/* static */ HRESULT HostVideoInputDevice::queryHostDevices(VirtualBox *pVirtualBox, HostVideoInputDeviceList *pList)
+{
+ HRESULT hr = fillDeviceList(pVirtualBox, pList);
+
+ if (FAILED(hr))
+ {
+ pList->clear();
+ }
+
+ return hr;
+}
+
+/* vi: set tabstop=4 shiftwidth=4 expandtab: */
diff --git a/src/VBox/Main/src-server/MachineImpl.cpp b/src/VBox/Main/src-server/MachineImpl.cpp
index 2ffa9b51..d7905917 100644
--- a/src/VBox/Main/src-server/MachineImpl.cpp
+++ b/src/VBox/Main/src-server/MachineImpl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2004-2012 Oracle Corporation
+ * Copyright (C) 2004-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -23,23 +23,17 @@
# define __STDC_CONSTANT_MACROS
#endif
-#ifdef VBOX_WITH_SYS_V_IPC_SESSION_WATCHER
-# include <errno.h>
-# include <sys/types.h>
-# include <sys/stat.h>
-# include <sys/ipc.h>
-# include <sys/sem.h>
-#endif
-
#include "Logging.h"
#include "VirtualBoxImpl.h"
#include "MachineImpl.h"
+#include "ClientToken.h"
#include "ProgressImpl.h"
#include "ProgressProxyImpl.h"
#include "MediumAttachmentImpl.h"
#include "MediumImpl.h"
#include "MediumLock.h"
#include "USBControllerImpl.h"
+#include "USBDeviceFiltersImpl.h"
#include "HostImpl.h"
#include "SharedFolderImpl.h"
#include "GuestOSTypeImpl.h"
@@ -48,9 +42,9 @@
#include "StorageControllerImpl.h"
#include "DisplayImpl.h"
#include "DisplayUtils.h"
-#include "BandwidthControlImpl.h"
#include "MachineImplCloneVM.h"
#include "AutostartDb.h"
+#include "SystemPropertiesImpl.h"
// generated header
#include "VBoxEvents.h"
@@ -73,6 +67,7 @@
#include <iprt/cpp/xml.h> /* xml::XmlFileWriter::s_psz*Suff. */
#include <iprt/sha.h>
#include <iprt/string.h>
+#include <iprt/base64.h>
#include <VBox/com/array.h>
#include <VBox/com/list.h>
@@ -161,14 +156,18 @@ Machine::HWData::HWData()
mCPUHotPlugEnabled = false;
mMemoryBalloonSize = 0;
mPageFusionEnabled = false;
+ mGraphicsControllerType = GraphicsControllerType_VBoxVGA;
mVRAMSize = 8;
mAccelerate3DEnabled = false;
mAccelerate2DVideoEnabled = false;
mMonitorCount = 1;
- mVideoCaptureFile = "Test.webm";
- mVideoCaptureWidth = 640;
- mVideoCaptureHeight = 480;
- mVideoCaptureEnabled = true;
+ mVideoCaptureWidth = 1024;
+ mVideoCaptureHeight = 768;
+ mVideoCaptureRate = 512;
+ mVideoCaptureFPS = 25;
+ mVideoCaptureEnabled = false;
+ for (unsigned i = 0; i < RT_ELEMENTS(maVideoCaptureScreens); i++)
+ maVideoCaptureScreens[i] = true;
mHWVirtExEnabled = true;
mHWVirtExNestedPagingEnabled = true;
@@ -179,18 +178,16 @@ Machine::HWData::HWData()
mHWVirtExLargePagesEnabled = false;
#endif
mHWVirtExVPIDEnabled = true;
+ mHWVirtExUXEnabled = true;
mHWVirtExForceEnabled = false;
-#if defined(RT_OS_DARWIN) || defined(RT_OS_WINDOWS)
- mHWVirtExExclusive = false;
-#else
- mHWVirtExExclusive = true;
-#endif
#if HC_ARCH_BITS == 64 || defined(RT_OS_WINDOWS) || defined(RT_OS_DARWIN)
mPAEEnabled = true;
#else
mPAEEnabled = false;
#endif
+ mLongMode = HC_ARCH_BITS == 64 ? settings::Hardware::LongMode_Enabled : settings::Hardware::LongMode_Disabled;
mSyntheticCpu = false;
+ mTripleFaultReset = false;
mHPETEnabled = false;
/* default boot order: floppy - DVD - HDD */
@@ -243,13 +240,15 @@ Machine::MediaData::~MediaData()
// constructor / destructor
/////////////////////////////////////////////////////////////////////////////
-Machine::Machine()
- : mCollectorGuest(NULL),
- mPeer(NULL),
- mParent(NULL),
- mSerialPorts(),
- mParallelPorts(),
- uRegistryNeedsSaving(0)
+Machine::Machine() :
+#ifdef VBOX_WITH_RESOURCE_USAGE_API
+ mCollectorGuest(NULL),
+#endif
+ mPeer(NULL),
+ mParent(NULL),
+ mSerialPorts(),
+ mParallelPorts(),
+ uRegistryNeedsSaving(0)
{}
Machine::~Machine()
@@ -349,6 +348,10 @@ HRESULT Machine::init(VirtualBox *aParent,
/* Apply serial port defaults */
for (ULONG slot = 0; slot < RT_ELEMENTS(mSerialPorts); ++slot)
mSerialPorts[slot]->applyDefaults(aOsType);
+
+ /* Let the OS type select 64-bit ness. */
+ mHWData->mLongMode = aOsType->is64Bit()
+ ? settings::Hardware::LongMode_Enabled : settings::Hardware::LongMode_Disabled;
}
/* At this point the changing of the current state modification
@@ -568,6 +571,10 @@ HRESULT Machine::init(VirtualBox *aParent,
autoInitSpan.setSucceeded();
else
{
+ /* Ignore all errors from unregistering, they would destroy
+ * the more interesting error information we already have,
+ * pinpointing the issue with the VM config. */
+ ErrorInfoKeeper eik;
autoInitSpan.setLimited();
// uninit media from this machine's media registry, or else
@@ -684,7 +691,7 @@ HRESULT Machine::registeredInit()
{
AssertReturn(!isSessionMachine(), E_FAIL);
AssertReturn(!isSnapshotMachine(), E_FAIL);
- AssertReturn(!mData->mUuid.isEmpty(), E_FAIL);
+ AssertReturn(mData->mUuid.isValid(), E_FAIL);
AssertReturn(!mData->mAccessible, E_FAIL);
HRESULT rc = initDataAndChildObjects();
@@ -853,7 +860,8 @@ void Machine::uninit()
* "cannot be closed because it is still attached to 1 virtual machines"
* because at this point we did not call uninitDataAndChildObjects() yet
* and therefore also removeBackReference() for all these mediums was not called! */
- if (!uuidMachine.isEmpty()) // can be empty if we're called from a failure of Machine::init
+
+ if (uuidMachine.isValid() && !uuidMachine.isZero()) // can be empty if we're called from a failure of Machine::init
mParent->unregisterMachineMedia(uuidMachine);
// has machine been modified?
@@ -898,6 +906,10 @@ STDMETHODIMP Machine::COMGETTER(Accessible)(BOOL *aAccessible)
LogFlowThisFunc(("ENTER\n"));
+ /* In some cases (medium registry related), it is necessary to be able to
+ * go through the list of all machines. Happens when an inaccessible VM
+ * has a sensible medium registry. */
+ AutoReadLock mllock(mParent->getMachinesListLockHandle() COMMA_LOCKVAL_SRC_POS);
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
HRESULT rc = S_OK;
@@ -999,8 +1011,9 @@ STDMETHODIMP Machine::COMSETTER(Name)(IN_BSTR aName)
// prohibit setting a UUID only as the machine name, or else it can
// never be found by findMachine()
Guid test(aName);
- if (test.isNotEmpty())
- return setError(E_INVALIDARG, tr("A machine cannot have a UUID as its name"));
+
+ if (test.isValid())
+ return setError(E_INVALIDARG, tr("A machine cannot have a UUID as its name"));
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
@@ -1274,8 +1287,8 @@ STDMETHODIMP Machine::COMSETTER(ChipsetType)(ChipsetType_T aChipsetType)
// Resize network adapter array, to be finalized on commit/rollback.
// We must not throw away entries yet, otherwise settings are lost
// without a way to roll back.
- uint32_t newCount = Global::getMaxNetworkAdapters(aChipsetType);
- uint32_t oldCount = mNetworkAdapters.size();
+ size_t newCount = Global::getMaxNetworkAdapters(aChipsetType);
+ size_t oldCount = mNetworkAdapters.size();
if (newCount > oldCount)
{
mNetworkAdapters.resize(newCount);
@@ -1337,7 +1350,7 @@ STDMETHODIMP Machine::COMGETTER(HardwareUUID)(BSTR *aUUID)
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
- if (!mHWData->mHardwareUUID.isEmpty())
+ if (!mHWData->mHardwareUUID.isZero())
mHWData->mHardwareUUID.toUtf16().cloneTo(aUUID);
else
mData->mUuid.toUtf16().cloneTo(aUUID);
@@ -1348,7 +1361,7 @@ STDMETHODIMP Machine::COMGETTER(HardwareUUID)(BSTR *aUUID)
STDMETHODIMP Machine::COMSETTER(HardwareUUID)(IN_BSTR aUUID)
{
Guid hardwareUUID(aUUID);
- if (hardwareUUID.isEmpty())
+ if (!hardwareUUID.isValid())
return E_INVALIDARG;
AutoCaller autoCaller(this);
@@ -1500,7 +1513,7 @@ STDMETHODIMP Machine::COMSETTER(CPUExecutionCap)(ULONG aExecutionCap)
mHWData.backup();
mHWData->mCpuExecutionCap = aExecutionCap;
- /* Save settings if online - todo why is this required?? */
+ /** Save settings if online - @todo why is this required? -- @bugref{6818} */
if (Global::IsOnline(mData->mMachineState))
saveSettings(NULL);
@@ -1508,21 +1521,21 @@ STDMETHODIMP Machine::COMSETTER(CPUExecutionCap)(ULONG aExecutionCap)
}
-STDMETHODIMP Machine::COMGETTER(CPUHotPlugEnabled)(BOOL *enabled)
+STDMETHODIMP Machine::COMGETTER(CPUHotPlugEnabled)(BOOL *aEnabled)
{
- CheckComArgOutPointerValid(enabled);
+ CheckComArgOutPointerValid(aEnabled);
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
- *enabled = mHWData->mCPUHotPlugEnabled;
+ *aEnabled = mHWData->mCPUHotPlugEnabled;
return S_OK;
}
-STDMETHODIMP Machine::COMSETTER(CPUHotPlugEnabled)(BOOL enabled)
+STDMETHODIMP Machine::COMSETTER(CPUHotPlugEnabled)(BOOL aEnabled)
{
HRESULT rc = S_OK;
@@ -1534,9 +1547,9 @@ STDMETHODIMP Machine::COMSETTER(CPUHotPlugEnabled)(BOOL enabled)
rc = checkStateDependency(MutableStateDep);
if (FAILED(rc)) return rc;
- if (mHWData->mCPUHotPlugEnabled != enabled)
+ if (mHWData->mCPUHotPlugEnabled != aEnabled)
{
- if (enabled)
+ if (aEnabled)
{
setModified(IsModified_MachineData);
mHWData.backup();
@@ -1575,31 +1588,31 @@ STDMETHODIMP Machine::COMSETTER(CPUHotPlugEnabled)(BOOL enabled)
}
}
- mHWData->mCPUHotPlugEnabled = enabled;
+ mHWData->mCPUHotPlugEnabled = aEnabled;
return rc;
}
-STDMETHODIMP Machine::COMGETTER(EmulatedUSBCardReaderEnabled)(BOOL *enabled)
+STDMETHODIMP Machine::COMGETTER(EmulatedUSBCardReaderEnabled)(BOOL *aEnabled)
{
#ifdef VBOX_WITH_USB_CARDREADER
- CheckComArgOutPointerValid(enabled);
+ CheckComArgOutPointerValid(aEnabled);
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
- *enabled = mHWData->mEmulatedUSBCardReaderEnabled;
+ *aEnabled = mHWData->mEmulatedUSBCardReaderEnabled;
return S_OK;
#else
- NOREF(enabled);
+ NOREF(aEnabled);
return E_NOTIMPL;
#endif
}
-STDMETHODIMP Machine::COMSETTER(EmulatedUSBCardReaderEnabled)(BOOL enabled)
+STDMETHODIMP Machine::COMSETTER(EmulatedUSBCardReaderEnabled)(BOOL aEnabled)
{
#ifdef VBOX_WITH_USB_CARDREADER
AutoCaller autoCaller(this);
@@ -1611,41 +1624,29 @@ STDMETHODIMP Machine::COMSETTER(EmulatedUSBCardReaderEnabled)(BOOL enabled)
setModified(IsModified_MachineData);
mHWData.backup();
- mHWData->mEmulatedUSBCardReaderEnabled = enabled;
+ mHWData->mEmulatedUSBCardReaderEnabled = aEnabled;
return S_OK;
#else
- NOREF(enabled);
+ NOREF(aEnabled);
return E_NOTIMPL;
#endif
}
-STDMETHODIMP Machine::COMGETTER(EmulatedUSBWebcameraEnabled)(BOOL *enabled)
-{
- NOREF(enabled);
- return E_NOTIMPL;
-}
-
-STDMETHODIMP Machine::COMSETTER(EmulatedUSBWebcameraEnabled)(BOOL enabled)
-{
- NOREF(enabled);
- return E_NOTIMPL;
-}
-
-STDMETHODIMP Machine::COMGETTER(HPETEnabled)(BOOL *enabled)
+STDMETHODIMP Machine::COMGETTER(HPETEnabled)(BOOL *aEnabled)
{
- CheckComArgOutPointerValid(enabled);
+ CheckComArgOutPointerValid(aEnabled);
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
- *enabled = mHWData->mHPETEnabled;
+ *aEnabled = mHWData->mHPETEnabled;
return S_OK;
}
-STDMETHODIMP Machine::COMSETTER(HPETEnabled)(BOOL enabled)
+STDMETHODIMP Machine::COMSETTER(HPETEnabled)(BOOL aEnabled)
{
HRESULT rc = S_OK;
@@ -1659,12 +1660,12 @@ STDMETHODIMP Machine::COMSETTER(HPETEnabled)(BOOL enabled)
setModified(IsModified_MachineData);
mHWData.backup();
- mHWData->mHPETEnabled = enabled;
+ mHWData->mHPETEnabled = aEnabled;
return rc;
}
-STDMETHODIMP Machine::COMGETTER(VideoCaptureEnabled)(BOOL * fEnabled)
+STDMETHODIMP Machine::COMGETTER(VideoCaptureEnabled)(BOOL *fEnabled)
{
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
@@ -1675,23 +1676,102 @@ STDMETHODIMP Machine::COMGETTER(VideoCaptureEnabled)(BOOL * fEnabled)
return S_OK;
}
-STDMETHODIMP Machine::COMSETTER(VideoCaptureEnabled)(BOOL fEnabled)
+STDMETHODIMP Machine::COMSETTER(VideoCaptureEnabled)(BOOL fEnabled)
{
+ HRESULT rc = S_OK;
+
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ setModified(IsModified_MachineData);
+ mHWData.backup();
mHWData->mVideoCaptureEnabled = fEnabled;
+
+ alock.release();
+ rc = onVideoCaptureChange();
+ alock.acquire();
+ if (FAILED(rc))
+ {
+ /*
+ * Normally we would do the actual change _after_ onVideoCaptureChange() succeeded.
+ * We cannot do this because that function uses Machine::GetVideoCaptureEnabled to
+ * determine if it should start or stop capturing. Therefore we need to manually
+ * undo change.
+ */
+ mHWData->mVideoCaptureEnabled = mHWData.backedUpData()->mVideoCaptureEnabled;
+ return rc;
+ }
+
+ /** Save settings if online - @todo why is this required? -- @bugref{6818} */
+ if (Global::IsOnline(mData->mMachineState))
+ saveSettings(NULL);
+
+ return rc;
+}
+
+STDMETHODIMP Machine::COMGETTER(VideoCaptureScreens)(ComSafeArrayOut(BOOL, aScreens))
+{
+ CheckComArgOutSafeArrayPointerValid(aScreens);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ SafeArray<BOOL> screens(mHWData->mMonitorCount);
+ for (unsigned i = 0; i < screens.size(); i++)
+ screens[i] = mHWData->maVideoCaptureScreens[i];
+ screens.detachTo(ComSafeArrayOutArg(aScreens));
+ return S_OK;
+}
+
+STDMETHODIMP Machine::COMSETTER(VideoCaptureScreens)(ComSafeArrayIn(BOOL, aScreens))
+{
+ SafeArray<BOOL> screens(ComSafeArrayInArg(aScreens));
+ AssertReturn(screens.size() <= RT_ELEMENTS(mHWData->maVideoCaptureScreens), E_INVALIDARG);
+ bool fChanged = false;
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ for (unsigned i = 0; i < screens.size(); i++)
+ {
+ if (mHWData->maVideoCaptureScreens[i] != RT_BOOL(screens[i]))
+ {
+ mHWData->maVideoCaptureScreens[i] = RT_BOOL(screens[i]);
+ fChanged = true;
+ }
+ }
+ if (fChanged)
+ {
+ alock.release();
+ HRESULT rc = onVideoCaptureChange();
+ alock.acquire();
+ if (FAILED(rc)) return rc;
+ setModified(IsModified_MachineData);
+
+ /** Save settings if online - @todo why is this required? -- @bugref{6818} */
+ if (Global::IsOnline(mData->mMachineState))
+ saveSettings(NULL);
+ }
+
return S_OK;
}
-STDMETHODIMP Machine::COMGETTER(VideoCaptureFile)(BSTR * apFile)
+STDMETHODIMP Machine::COMGETTER(VideoCaptureFile)(BSTR *apFile)
{
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
- mHWData->mVideoCaptureFile.cloneTo(apFile);
+ if (mHWData->mVideoCaptureFile.isEmpty())
+ {
+ Utf8Str defaultFile;
+ getDefaultVideoCaptureFile(defaultFile);
+ defaultFile.cloneTo(apFile);
+ }
+ else
+ mHWData->mVideoCaptureFile.cloneTo(apFile);
return S_OK;
}
@@ -1702,54 +1782,181 @@ STDMETHODIMP Machine::COMSETTER(VideoCaptureFile)(IN_BSTR aFile)
if (FAILED(autoCaller.rc())) return autoCaller.rc();
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
- if(strFile.isEmpty())
- strFile = "VideoCap.webm";
+
+ if ( Global::IsOnline(mData->mMachineState)
+ && mHWData->mVideoCaptureEnabled)
+ return setError(E_INVALIDARG, tr("Cannot change parameters while capturing is enabled"));
+
+ if (!RTPathStartsWithRoot(strFile.c_str()))
+ return setError(E_INVALIDARG, tr("Video capture file name '%s' is not absolute"), strFile.c_str());
+
+ if (!strFile.isEmpty())
+ {
+ Utf8Str defaultFile;
+ getDefaultVideoCaptureFile(defaultFile);
+ if (!RTPathCompare(strFile.c_str(), defaultFile.c_str()))
+ strFile.setNull();
+ }
+
+ setModified(IsModified_MachineData);
+ mHWData.backup();
mHWData->mVideoCaptureFile = strFile;
+
return S_OK;
}
+STDMETHODIMP Machine::COMGETTER(VideoCaptureWidth)(ULONG *aHorzRes)
+{
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
-STDMETHODIMP Machine::COMGETTER(VideoCaptureWidth)(ULONG *ulHorzRes)
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+ *aHorzRes = mHWData->mVideoCaptureWidth;
+ return S_OK;
+}
+
+STDMETHODIMP Machine::COMSETTER(VideoCaptureWidth)(ULONG aHorzRes)
+{
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if ( Global::IsOnline(mData->mMachineState)
+ && mHWData->mVideoCaptureEnabled)
+ return setError(E_INVALIDARG, tr("Cannot change parameters while capturing is enabled"));
+
+ setModified(IsModified_MachineData);
+ mHWData.backup();
+ mHWData->mVideoCaptureWidth = aHorzRes;
+
+ return S_OK;
+}
+
+STDMETHODIMP Machine::COMGETTER(VideoCaptureHeight)(ULONG *aVertRes)
{
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
- *ulHorzRes = mHWData->mVideoCaptureWidth;
+ *aVertRes = mHWData->mVideoCaptureHeight;
return S_OK;
}
-STDMETHODIMP Machine::COMSETTER(VideoCaptureWidth)(ULONG ulHorzRes)
+STDMETHODIMP Machine::COMSETTER(VideoCaptureHeight)(ULONG aVertRes)
{
AutoCaller autoCaller(this);
- if (FAILED(autoCaller.rc()))
- {
- LogFlow(("Autolocked failed\n"));
- return autoCaller.rc();
- }
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
- mHWData->mVideoCaptureWidth = ulHorzRes;
+
+ if ( Global::IsOnline(mData->mMachineState)
+ && mHWData->mVideoCaptureEnabled)
+ return setError(E_INVALIDARG, tr("Cannot change parameters while capturing is enabled"));
+
+ setModified(IsModified_MachineData);
+ mHWData.backup();
+ mHWData->mVideoCaptureHeight = aVertRes;
+
return S_OK;
}
-STDMETHODIMP Machine::COMGETTER(VideoCaptureHeight)(ULONG *ulVertRes)
+STDMETHODIMP Machine::COMGETTER(VideoCaptureRate)(ULONG *aRate)
{
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
- *ulVertRes = mHWData->mVideoCaptureHeight;
+ *aRate = mHWData->mVideoCaptureRate;
+ return S_OK;
+}
+
+STDMETHODIMP Machine::COMSETTER(VideoCaptureRate)(ULONG aRate)
+{
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if ( Global::IsOnline(mData->mMachineState)
+ && mHWData->mVideoCaptureEnabled)
+ return setError(E_INVALIDARG, tr("Cannot change parameters while capturing is enabled"));
+
+ setModified(IsModified_MachineData);
+ mHWData.backup();
+ mHWData->mVideoCaptureRate = aRate;
+
+ return S_OK;
+}
+
+STDMETHODIMP Machine::COMGETTER(VideoCaptureFPS)(ULONG *aFPS)
+{
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+ *aFPS = mHWData->mVideoCaptureFPS;
+ return S_OK;
+}
+
+STDMETHODIMP Machine::COMSETTER(VideoCaptureFPS)(ULONG aFPS)
+{
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if ( Global::IsOnline(mData->mMachineState)
+ && mHWData->mVideoCaptureEnabled)
+ return setError(E_INVALIDARG, tr("Cannot change parameters while capturing is enabled"));
+
+ setModified(IsModified_MachineData);
+ mHWData.backup();
+ mHWData->mVideoCaptureFPS = aFPS;
+
return S_OK;
}
-STDMETHODIMP Machine::COMSETTER(VideoCaptureHeight)(ULONG ulVertRes)
+STDMETHODIMP Machine::COMGETTER(GraphicsControllerType)(GraphicsControllerType_T *aGraphicsControllerType)
{
+ CheckComArgOutPointerValid(aGraphicsControllerType);
+
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
- mHWData->mVideoCaptureHeight = ulVertRes;
+
+ *aGraphicsControllerType = mHWData->mGraphicsControllerType;
+
+ return S_OK;
+}
+
+STDMETHODIMP Machine::COMSETTER(GraphicsControllerType)(GraphicsControllerType_T aGraphicsControllerType)
+{
+ switch (aGraphicsControllerType)
+ {
+ case GraphicsControllerType_Null:
+ case GraphicsControllerType_VBoxVGA:
+#ifdef VBOX_WITH_VMSVGA
+ case GraphicsControllerType_VMSVGA:
+#endif
+ break;
+ default:
+ return setError(E_INVALIDARG, tr("The graphics controller type (%d) is invalid"), aGraphicsControllerType);
+ }
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ HRESULT rc = checkStateDependency(MutableStateDep);
+ if (FAILED(rc)) return rc;
+
+ setModified(IsModified_MachineData);
+ mHWData.backup();
+ mHWData->mGraphicsControllerType = aGraphicsControllerType;
+
return S_OK;
}
@@ -1838,20 +2045,20 @@ STDMETHODIMP Machine::COMSETTER(MemoryBalloonSize)(ULONG memoryBalloonSize)
#endif
}
-STDMETHODIMP Machine::COMGETTER(PageFusionEnabled) (BOOL *enabled)
+STDMETHODIMP Machine::COMGETTER(PageFusionEnabled) (BOOL *aEnabled)
{
- CheckComArgOutPointerValid(enabled);
+ CheckComArgOutPointerValid(aEnabled);
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
- *enabled = mHWData->mPageFusionEnabled;
+ *aEnabled = mHWData->mPageFusionEnabled;
return S_OK;
}
-STDMETHODIMP Machine::COMSETTER(PageFusionEnabled) (BOOL enabled)
+STDMETHODIMP Machine::COMSETTER(PageFusionEnabled) (BOOL aEnabled)
{
#ifdef VBOX_WITH_PAGE_SHARING
AutoCaller autoCaller(this);
@@ -1862,24 +2069,24 @@ STDMETHODIMP Machine::COMSETTER(PageFusionEnabled) (BOOL enabled)
/** @todo must support changes for running vms and keep this in sync with IGuest. */
setModified(IsModified_MachineData);
mHWData.backup();
- mHWData->mPageFusionEnabled = enabled;
+ mHWData->mPageFusionEnabled = aEnabled;
return S_OK;
#else
- NOREF(enabled);
+ NOREF(aEnabled);
return setError(E_NOTIMPL, tr("Page fusion is only supported on 64-bit hosts"));
#endif
}
-STDMETHODIMP Machine::COMGETTER(Accelerate3DEnabled)(BOOL *enabled)
+STDMETHODIMP Machine::COMGETTER(Accelerate3DEnabled)(BOOL *aEnabled)
{
- CheckComArgOutPointerValid(enabled);
+ CheckComArgOutPointerValid(aEnabled);
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
- *enabled = mHWData->mAccelerate3DEnabled;
+ *aEnabled = mHWData->mAccelerate3DEnabled;
return S_OK;
}
@@ -1904,16 +2111,16 @@ STDMETHODIMP Machine::COMSETTER(Accelerate3DEnabled)(BOOL enable)
}
-STDMETHODIMP Machine::COMGETTER(Accelerate2DVideoEnabled)(BOOL *enabled)
+STDMETHODIMP Machine::COMGETTER(Accelerate2DVideoEnabled)(BOOL *aEnabled)
{
- CheckComArgOutPointerValid(enabled);
+ CheckComArgOutPointerValid(aEnabled);
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
- *enabled = mHWData->mAccelerate2DVideoEnabled;
+ *aEnabled = mHWData->mAccelerate2DVideoEnabled;
return S_OK;
}
@@ -1996,18 +2203,55 @@ STDMETHODIMP Machine::GetCPUProperty(CPUPropertyType_T property, BOOL *aVal)
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
- switch(property)
+ switch (property)
{
- case CPUPropertyType_PAE:
- *aVal = mHWData->mPAEEnabled;
- break;
+ case CPUPropertyType_PAE:
+ *aVal = mHWData->mPAEEnabled;
+ break;
- case CPUPropertyType_Synthetic:
- *aVal = mHWData->mSyntheticCpu;
- break;
+ case CPUPropertyType_Synthetic:
+ *aVal = mHWData->mSyntheticCpu;
+ break;
- default:
- return E_INVALIDARG;
+ case CPUPropertyType_LongMode:
+ if (mHWData->mLongMode == settings::Hardware::LongMode_Enabled)
+ *aVal = TRUE;
+ else if (mHWData->mLongMode == settings::Hardware::LongMode_Disabled)
+ *aVal = FALSE;
+#if HC_ARCH_BITS == 64
+ else
+ *aVal = TRUE;
+#else
+ else
+ {
+ *aVal = FALSE;
+
+ ComPtr<IGuestOSType> ptrGuestOSType;
+ HRESULT hrc2 = mParent->GetGuestOSType(Bstr(mUserData->s.strOsType).raw(), ptrGuestOSType.asOutParam());
+ if (SUCCEEDED(hrc2))
+ {
+ BOOL fIs64Bit = FALSE;
+ hrc2 = ptrGuestOSType->COMGETTER(Is64Bit)(&fIs64Bit); AssertComRC(hrc2);
+ if (SUCCEEDED(hrc2) && fIs64Bit)
+ {
+ ComObjPtr<Host> ptrHost = mParent->host();
+ alock.release();
+
+ hrc2 = ptrHost->GetProcessorFeature(ProcessorFeature_LongMode, aVal); AssertComRC(hrc2);
+ if (FAILED(hrc2))
+ *aVal = FALSE;
+ }
+ }
+ }
+#endif
+ break;
+
+ case CPUPropertyType_TripleFaultReset:
+ *aVal = mHWData->mTripleFaultReset;
+ break;
+
+ default:
+ return E_INVALIDARG;
}
return S_OK;
}
@@ -2022,22 +2266,34 @@ STDMETHODIMP Machine::SetCPUProperty(CPUPropertyType_T property, BOOL aVal)
HRESULT rc = checkStateDependency(MutableStateDep);
if (FAILED(rc)) return rc;
- switch(property)
+ switch (property)
{
- case CPUPropertyType_PAE:
- setModified(IsModified_MachineData);
- mHWData.backup();
- mHWData->mPAEEnabled = !!aVal;
- break;
+ case CPUPropertyType_PAE:
+ setModified(IsModified_MachineData);
+ mHWData.backup();
+ mHWData->mPAEEnabled = !!aVal;
+ break;
- case CPUPropertyType_Synthetic:
- setModified(IsModified_MachineData);
- mHWData.backup();
- mHWData->mSyntheticCpu = !!aVal;
- break;
+ case CPUPropertyType_Synthetic:
+ setModified(IsModified_MachineData);
+ mHWData.backup();
+ mHWData->mSyntheticCpu = !!aVal;
+ break;
- default:
- return E_INVALIDARG;
+ case CPUPropertyType_LongMode:
+ setModified(IsModified_MachineData);
+ mHWData.backup();
+ mHWData->mLongMode = !aVal ? settings::Hardware::LongMode_Disabled : settings::Hardware::LongMode_Enabled;
+ break;
+
+ case CPUPropertyType_TripleFaultReset:
+ setModified(IsModified_MachineData);
+ mHWData.backup();
+ mHWData->mTripleFaultReset = !!aVal;
+ break;
+
+ default:
+ return E_INVALIDARG;
}
return S_OK;
}
@@ -2259,10 +2515,6 @@ STDMETHODIMP Machine::GetHWVirtExProperty(HWVirtExPropertyType_T property, BOOL
*aVal = mHWData->mHWVirtExEnabled;
break;
- case HWVirtExPropertyType_Exclusive:
- *aVal = mHWData->mHWVirtExExclusive;
- break;
-
case HWVirtExPropertyType_VPID:
*aVal = mHWData->mHWVirtExVPIDEnabled;
break;
@@ -2271,6 +2523,10 @@ STDMETHODIMP Machine::GetHWVirtExProperty(HWVirtExPropertyType_T property, BOOL
*aVal = mHWData->mHWVirtExNestedPagingEnabled;
break;
+ case HWVirtExPropertyType_UnrestrictedExecution:
+ *aVal = mHWData->mHWVirtExUXEnabled;
+ break;
+
case HWVirtExPropertyType_LargePages:
*aVal = mHWData->mHWVirtExLargePagesEnabled;
#if defined(DEBUG_bird) && defined(RT_OS_LINUX) /* This feature is deadly here */
@@ -2306,12 +2562,6 @@ STDMETHODIMP Machine::SetHWVirtExProperty(HWVirtExPropertyType_T property, BOOL
mHWData->mHWVirtExEnabled = !!aVal;
break;
- case HWVirtExPropertyType_Exclusive:
- setModified(IsModified_MachineData);
- mHWData.backup();
- mHWData->mHWVirtExExclusive = !!aVal;
- break;
-
case HWVirtExPropertyType_VPID:
setModified(IsModified_MachineData);
mHWData.backup();
@@ -2324,6 +2574,12 @@ STDMETHODIMP Machine::SetHWVirtExProperty(HWVirtExPropertyType_T property, BOOL
mHWData->mHWVirtExNestedPagingEnabled = !!aVal;
break;
+ case HWVirtExPropertyType_UnrestrictedExecution:
+ setModified(IsModified_MachineData);
+ mHWData.backup();
+ mHWData->mHWVirtExUXEnabled = !!aVal;
+ break;
+
case HWVirtExPropertyType_LargePages:
setModified(IsModified_MachineData);
mHWData.backup();
@@ -2444,10 +2700,40 @@ STDMETHODIMP Machine::COMGETTER(AudioAdapter)(IAudioAdapter **audioAdapter)
return S_OK;
}
-STDMETHODIMP Machine::COMGETTER(USBController)(IUSBController **aUSBController)
+STDMETHODIMP Machine::COMGETTER(USBControllers)(ComSafeArrayOut(IUSBController *, aUSBControllers))
+{
+#ifdef VBOX_WITH_VUSB
+ CheckComArgOutPointerValid(aUSBControllers);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ clearError();
+ MultiResult rc(S_OK);
+
+# ifdef VBOX_WITH_USB
+ rc = mParent->host()->checkUSBProxyService();
+ if (FAILED(rc)) return rc;
+# endif
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ SafeIfaceArray<IUSBController> ctrls(*mUSBControllers.data());
+ ctrls.detachTo(ComSafeArrayOutArg(aUSBControllers));
+ return S_OK;
+#else
+ /* Note: The GUI depends on this method returning E_NOTIMPL with no
+ * extended error info to indicate that USB is simply not available
+ * (w/o treating it as a failure), for example, as in OSE */
+ NOREF(aUSBControllers);
+ ReturnComNotImplemented();
+#endif /* VBOX_WITH_VUSB */
+}
+
+STDMETHODIMP Machine::COMGETTER(USBDeviceFilters)(IUSBDeviceFilters **aUSBDeviceFilters)
{
#ifdef VBOX_WITH_VUSB
- CheckComArgOutPointerValid(aUSBController);
+ CheckComArgOutPointerValid(aUSBDeviceFilters);
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
@@ -2462,12 +2748,12 @@ STDMETHODIMP Machine::COMGETTER(USBController)(IUSBController **aUSBController)
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
- return rc = mUSBController.queryInterfaceTo(aUSBController);
+ return rc = mUSBDeviceFilters.queryInterfaceTo(aUSBDeviceFilters);
#else
/* Note: The GUI depends on this method returning E_NOTIMPL with no
* extended error info to indicate that USB is simply not available
* (w/o treating it as a failure), for example, as in OSE */
- NOREF(aUSBController);
+ NOREF(aUSBDeviceFilters);
ReturnComNotImplemented();
#endif /* VBOX_WITH_VUSB */
}
@@ -2685,8 +2971,7 @@ STDMETHODIMP Machine::COMGETTER(ClipboardMode)(ClipboardMode_T *aClipboardMode)
return S_OK;
}
-STDMETHODIMP
-Machine::COMSETTER(ClipboardMode)(ClipboardMode_T aClipboardMode)
+STDMETHODIMP Machine::COMSETTER(ClipboardMode)(ClipboardMode_T aClipboardMode)
{
HRESULT rc = S_OK;
@@ -2704,7 +2989,7 @@ Machine::COMSETTER(ClipboardMode)(ClipboardMode_T aClipboardMode)
mHWData.backup();
mHWData->mClipboardMode = aClipboardMode;
- /* Save settings if online - todo why is this required?? */
+ /** Save settings if online - @todo why is this required? -- @bugref{6818} */
if (Global::IsOnline(mData->mMachineState))
saveSettings(NULL);
@@ -2725,8 +3010,7 @@ STDMETHODIMP Machine::COMGETTER(DragAndDropMode)(DragAndDropMode_T *aDragAndDrop
return S_OK;
}
-STDMETHODIMP
-Machine::COMSETTER(DragAndDropMode)(DragAndDropMode_T aDragAndDropMode)
+STDMETHODIMP Machine::COMSETTER(DragAndDropMode)(DragAndDropMode_T aDragAndDropMode)
{
HRESULT rc = S_OK;
@@ -2744,15 +3028,14 @@ Machine::COMSETTER(DragAndDropMode)(DragAndDropMode_T aDragAndDropMode)
mHWData.backup();
mHWData->mDragAndDropMode = aDragAndDropMode;
- /* Save settings if online - todo why is this required?? */
+ /** Save settings if online - @todo why is this required? -- @bugref{6818} */
if (Global::IsOnline(mData->mMachineState))
saveSettings(NULL);
return S_OK;
}
-STDMETHODIMP
-Machine::COMGETTER(GuestPropertyNotificationPatterns)(BSTR *aPatterns)
+STDMETHODIMP Machine::COMGETTER(GuestPropertyNotificationPatterns)(BSTR *aPatterns)
{
CheckComArgOutPointerValid(aPatterns);
@@ -2773,8 +3056,7 @@ Machine::COMGETTER(GuestPropertyNotificationPatterns)(BSTR *aPatterns)
return S_OK;
}
-STDMETHODIMP
-Machine::COMSETTER(GuestPropertyNotificationPatterns)(IN_BSTR aPatterns)
+STDMETHODIMP Machine::COMSETTER(GuestPropertyNotificationPatterns)(IN_BSTR aPatterns)
{
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
@@ -2790,8 +3072,7 @@ Machine::COMSETTER(GuestPropertyNotificationPatterns)(IN_BSTR aPatterns)
return rc;
}
-STDMETHODIMP
-Machine::COMGETTER(StorageControllers)(ComSafeArrayOut(IStorageController *, aStorageControllers))
+STDMETHODIMP Machine::COMGETTER(StorageControllers)(ComSafeArrayOut(IStorageController *, aStorageControllers))
{
CheckComArgOutSafeArrayPointerValid(aStorageControllers);
@@ -2806,8 +3087,7 @@ Machine::COMGETTER(StorageControllers)(ComSafeArrayOut(IStorageController *, aSt
return S_OK;
}
-STDMETHODIMP
-Machine::COMGETTER(TeleporterEnabled)(BOOL *aEnabled)
+STDMETHODIMP Machine::COMGETTER(TeleporterEnabled)(BOOL *aEnabled)
{
CheckComArgOutPointerValid(aEnabled);
@@ -3301,7 +3581,7 @@ STDMETHODIMP Machine::LockMachine(ISession *aSession,
if (FAILED(rc))
// the failure may occur w/o any error info (from RPC), so provide one
return setError(VBOX_E_VM_ERROR,
- tr("Failed to get a console object from the direct session (%Rrc)"), rc);
+ tr("Failed to get a console object from the direct session (%Rhrc)"), rc);
ComAssertRet(!pConsoleW.isNull(), E_FAIL);
@@ -3313,7 +3593,7 @@ STDMETHODIMP Machine::LockMachine(ISession *aSession,
if (FAILED(rc))
// the failure may occur w/o any error info (from RPC), so provide one
return setError(VBOX_E_VM_ERROR,
- tr("Failed to assign the machine to the session (%Rrc)"), rc);
+ tr("Failed to assign the machine to the session (%Rhrc)"), rc);
alock.acquire();
// need to revalidate the state after acquiring the lock again
@@ -3354,6 +3634,17 @@ STDMETHODIMP Machine::LockMachine(ISession *aSession,
if (fLaunchingVMProcess)
{
+ if (mData->mSession.mPID == NIL_RTPROCESS)
+ {
+ // two or more clients racing for a lock, the one which set the
+ // session state to Spawning will win, the others will get an
+ // error as we can't decide here if waiting a little would help
+ // (only for shared locks this would avoid an error)
+ return setError(VBOX_E_INVALID_OBJECT_STATE,
+ tr("The machine '%s' already has a lock request pending"),
+ mUserData->s.strName.c_str());
+ }
+
// this machine is awaiting for a spawning session to be opened:
// then the calling process must be the one that got started by
// LaunchVMProcess()
@@ -3390,6 +3681,19 @@ STDMETHODIMP Machine::LockMachine(ISession *aSession,
SessionState_T origState = mData->mSession.mState;
mData->mSession.mState = SessionState_Spawning;
+#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER
+ /* Get the client token ID to be passed to the client process */
+ Utf8Str strTokenId;
+ sessionMachine->getTokenId(strTokenId);
+ Assert(!strTokenId.isEmpty());
+#else /* VBOX_WITH_GENERIC_SESSION_WATCHER */
+ /* Get the client token to be passed to the client process */
+ ComPtr<IToken> pToken(sessionMachine->getToken());
+ /* The token is now "owned" by pToken, fix refcount */
+ if (!pToken.isNull())
+ pToken->Release();
+#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */
+
/*
* Release the lock before calling the client process -- it will call
* Machine/SessionMachine methods. Releasing the lock here is quite safe
@@ -3403,13 +3707,19 @@ STDMETHODIMP Machine::LockMachine(ISession *aSession,
alock.release();
LogFlowThisFunc(("Calling AssignMachine()...\n"));
- rc = pSessionControl->AssignMachine(sessionMachine, lockType);
+#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER
+ rc = pSessionControl->AssignMachine(sessionMachine, lockType, Bstr(strTokenId).raw());
+#else /* VBOX_WITH_GENERIC_SESSION_WATCHER */
+ rc = pSessionControl->AssignMachine(sessionMachine, lockType, pToken);
+ /* Now the token is owned by the client process. */
+ pToken.setNull();
+#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */
LogFlowThisFunc(("AssignMachine() returned %08X\n", rc));
/* The failure may occur w/o any error info (from RPC), so provide one */
if (FAILED(rc))
setError(VBOX_E_VM_ERROR,
- tr("Failed to assign the machine to the session (%Rrc)"), rc);
+ tr("Failed to assign the machine to the session (%Rhrc)"), rc);
if ( SUCCEEDED(rc)
&& fLaunchingVMProcess
@@ -3442,7 +3752,7 @@ STDMETHODIMP Machine::LockMachine(ISession *aSession,
/* The failure may occur w/o any error info (from RPC), so provide one */
if (FAILED(rc))
setError(VBOX_E_VM_ERROR,
- tr("Failed to assign the machine to the remote session (%Rrc)"), rc);
+ tr("Failed to assign the machine to the remote session (%Rhrc)"), rc);
}
if (FAILED(rc))
@@ -3470,7 +3780,7 @@ STDMETHODIMP Machine::LockMachine(ISession *aSession,
{
/* Close the remote session, remove the remote control from the list
* and reset session state to Closed (@note keep the code in sync
- * with the relevant part in openSession()). */
+ * with the relevant part in checkForSpawnFailure()). */
Assert(mData->mSession.mRemoteControls.size() == 1);
if (mData->mSession.mRemoteControls.size() == 1)
@@ -3535,28 +3845,52 @@ STDMETHODIMP Machine::LockMachine(ISession *aSession,
* @note Locks objects!
*/
STDMETHODIMP Machine::LaunchVMProcess(ISession *aSession,
- IN_BSTR aType,
+ IN_BSTR aFrontend,
IN_BSTR aEnvironment,
IProgress **aProgress)
{
- CheckComArgStrNotEmptyOrNull(aType);
- Utf8Str strType(aType);
+ CheckComArgStr(aFrontend);
+ Utf8Str strFrontend(aFrontend);
Utf8Str strEnvironment(aEnvironment);
/* "emergencystop" doesn't need the session, so skip the checks/interface
* retrieval. This code doesn't quite fit in here, but introducing a
* special API method would be even more effort, and would require explicit
* support by every API client. It's better to hide the feature a bit. */
- if (strType != "emergencystop")
+ if (strFrontend != "emergencystop")
CheckComArgNotNull(aSession);
CheckComArgOutPointerValid(aProgress);
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
- ComPtr<IInternalSessionControl> control;
HRESULT rc = S_OK;
+ if (strFrontend.isEmpty())
+ {
+ Bstr bstrFrontend;
+ rc = COMGETTER(DefaultFrontend)(bstrFrontend.asOutParam());
+ if (FAILED(rc))
+ return rc;
+ strFrontend = bstrFrontend;
+ if (strFrontend.isEmpty())
+ {
+ ComPtr<ISystemProperties> systemProperties;
+ rc = mParent->COMGETTER(SystemProperties)(systemProperties.asOutParam());
+ if (FAILED(rc))
+ return rc;
+ rc = systemProperties->COMGETTER(DefaultFrontend)(bstrFrontend.asOutParam());
+ if (FAILED(rc))
+ return rc;
+ strFrontend = bstrFrontend;
+ }
+ /* paranoia - emergencystop is not a valid default */
+ if (strFrontend == "emergencystop")
+ strFrontend = Utf8Str::Empty;
+ }
+ /* default frontend: Qt GUI */
+ if (strFrontend.isEmpty())
+ strFrontend = "GUI/Qt";
- if (strType != "emergencystop")
+ if (strFrontend != "emergencystop")
{
/* check the session state */
SessionState_T state;
@@ -3569,21 +3903,18 @@ STDMETHODIMP Machine::LaunchVMProcess(ISession *aSession,
tr("The given session is busy"));
/* get the IInternalSessionControl interface */
- control = aSession;
+ ComPtr<IInternalSessionControl> control(aSession);
ComAssertMsgRet(!control.isNull(),
("No IInternalSessionControl interface"),
E_INVALIDARG);
- }
- /* get the teleporter enable state for the progress object init. */
- BOOL fTeleporterEnabled;
- rc = COMGETTER(TeleporterEnabled)(&fTeleporterEnabled);
- if (FAILED(rc))
- return rc;
+ /* get the teleporter enable state for the progress object init. */
+ BOOL fTeleporterEnabled;
+ rc = COMGETTER(TeleporterEnabled)(&fTeleporterEnabled);
+ if (FAILED(rc))
+ return rc;
- /* create a progress object */
- if (strType != "emergencystop")
- {
+ /* create a progress object */
ComObjPtr<ProgressProxy> progress;
progress.createObject();
rc = progress->init(mParent,
@@ -3591,13 +3922,13 @@ STDMETHODIMP Machine::LaunchVMProcess(ISession *aSession,
Bstr(tr("Starting VM")).raw(),
TRUE /* aCancelable */,
fTeleporterEnabled ? 20 : 10 /* uTotalOperationsWeight */,
- BstrFmt(tr("Creating process for virtual machine \"%s\" (%s)"), mUserData->s.strName.c_str(), strType.c_str()).raw(),
+ BstrFmt(tr("Creating process for virtual machine \"%s\" (%s)"), mUserData->s.strName.c_str(), strFrontend.c_str()).raw(),
2 /* uFirstOperationWeight */,
fTeleporterEnabled ? 3 : 1 /* cOtherProgressObjectOperations */);
if (SUCCEEDED(rc))
{
- rc = launchVMProcess(control, strType, strEnvironment, progress);
+ rc = launchVMProcess(control, strFrontend, strEnvironment, progress);
if (SUCCEEDED(rc))
{
progress.queryInterfaceTo(aProgress);
@@ -3725,9 +4056,18 @@ STDMETHODIMP Machine::AttachDevice(IN_BSTR aControllerName,
tr("Could not get type of controller '%ls'"),
aControllerName);
+ bool fSilent = false;
+ Utf8Str strReconfig;
+
+ /* Check whether the flag to allow silent storage attachment reconfiguration is set. */
+ strReconfig = getExtraData(Utf8Str("VBoxInternal2/SilentReconfigureWhilePaused"));
+ if ( mData->mMachineState == MachineState_Paused
+ && strReconfig == "1")
+ fSilent = true;
+
/* Check that the controller can do hotplugging if we detach the device while the VM is running. */
bool fHotplug = false;
- if (Global::IsOnlineOrTransient(mData->mMachineState))
+ if (!fSilent && Global::IsOnlineOrTransient(mData->mMachineState))
fHotplug = true;
if (fHotplug && !isControllerHotplugCapable(ctrlType))
@@ -3834,6 +4174,46 @@ STDMETHODIMP Machine::AttachDevice(IN_BSTR aControllerName,
/* the simplest case: restore the whole attachment
* and return, nothing else to do */
mMediaData->mAttachments.push_back(pAttachTemp);
+
+ /* Reattach the medium to the VM. */
+ if (fHotplug || fSilent)
+ {
+ mediumLock.release();
+ treeLock.release();
+ alock.release();
+
+ MediumLockList *pMediumLockList(new MediumLockList());
+
+ rc = medium->createMediumLockList(true /* fFailIfInaccessible */,
+ true /* fMediumLockWrite */,
+ NULL,
+ *pMediumLockList);
+ alock.acquire();
+ if (FAILED(rc))
+ delete pMediumLockList;
+ else
+ {
+ mData->mSession.mLockedMedia.Unlock();
+ alock.release();
+ rc = mData->mSession.mLockedMedia.Insert(pAttachTemp, pMediumLockList);
+ mData->mSession.mLockedMedia.Lock();
+ alock.acquire();
+ }
+ alock.release();
+
+ if (SUCCEEDED(rc))
+ {
+ rc = onStorageDeviceChange(pAttachTemp, FALSE /* aRemove */, fSilent);
+ /* Remove lock list in case of error. */
+ if (FAILED(rc))
+ {
+ mData->mSession.mLockedMedia.Unlock();
+ mData->mSession.mLockedMedia.Remove(pAttachTemp);
+ mData->mSession.mLockedMedia.Lock();
+ }
+ }
+ }
+
return S_OK;
}
@@ -3893,6 +4273,46 @@ STDMETHODIMP Machine::AttachDevice(IN_BSTR aControllerName,
/* the simplest case: restore the whole attachment
* and return, nothing else to do */
mMediaData->mAttachments.push_back(*it);
+
+ /* Reattach the medium to the VM. */
+ if (fHotplug || fSilent)
+ {
+ mediumLock.release();
+ treeLock.release();
+ alock.release();
+
+ MediumLockList *pMediumLockList(new MediumLockList());
+
+ rc = medium->createMediumLockList(true /* fFailIfInaccessible */,
+ true /* fMediumLockWrite */,
+ NULL,
+ *pMediumLockList);
+ alock.acquire();
+ if (FAILED(rc))
+ delete pMediumLockList;
+ else
+ {
+ mData->mSession.mLockedMedia.Unlock();
+ alock.release();
+ rc = mData->mSession.mLockedMedia.Insert(pAttachTemp, pMediumLockList);
+ mData->mSession.mLockedMedia.Lock();
+ alock.acquire();
+ }
+ alock.release();
+
+ if (SUCCEEDED(rc))
+ {
+ rc = onStorageDeviceChange(pAttachTemp, FALSE /* aRemove */, fSilent);
+ /* Remove lock list in case of error. */
+ if (FAILED(rc))
+ {
+ mData->mSession.mLockedMedia.Unlock();
+ mData->mSession.mLockedMedia.Remove(pAttachTemp);
+ mData->mSession.mLockedMedia.Lock();
+ }
+ }
+ }
+
return S_OK;
}
else if ( foundIt == oldAtts.end()
@@ -4098,6 +4518,7 @@ STDMETHODIMP Machine::AttachDevice(IN_BSTR aControllerName,
false /* fTempEject */,
false /* fNonRotational */,
false /* fDiscard */,
+ false /* fHotPluggable */,
Utf8Str::Empty);
if (FAILED(rc)) return rc;
@@ -4126,8 +4547,42 @@ STDMETHODIMP Machine::AttachDevice(IN_BSTR aControllerName,
treeLock.release();
alock.release();
- if (fHotplug)
- rc = onStorageDeviceChange(attachment, FALSE /* aRemove */);
+ if (fHotplug || fSilent)
+ {
+ if (!medium.isNull())
+ {
+ MediumLockList *pMediumLockList(new MediumLockList());
+
+ rc = medium->createMediumLockList(true /* fFailIfInaccessible */,
+ true /* fMediumLockWrite */,
+ NULL,
+ *pMediumLockList);
+ alock.acquire();
+ if (FAILED(rc))
+ delete pMediumLockList;
+ else
+ {
+ mData->mSession.mLockedMedia.Unlock();
+ alock.release();
+ rc = mData->mSession.mLockedMedia.Insert(attachment, pMediumLockList);
+ mData->mSession.mLockedMedia.Lock();
+ alock.acquire();
+ }
+ alock.release();
+ }
+
+ if (SUCCEEDED(rc))
+ {
+ rc = onStorageDeviceChange(attachment, FALSE /* aRemove */, fSilent);
+ /* Remove lock list in case of error. */
+ if (FAILED(rc))
+ {
+ mData->mSession.mLockedMedia.Unlock();
+ mData->mSession.mLockedMedia.Remove(attachment);
+ mData->mSession.mLockedMedia.Lock();
+ }
+ }
+ }
mParent->saveModifiedRegistries();
@@ -4164,9 +4619,18 @@ STDMETHODIMP Machine::DetachDevice(IN_BSTR aControllerName, LONG aControllerPort
tr("Could not get type of controller '%ls'"),
aControllerName);
+ bool fSilent = false;
+ Utf8Str strReconfig;
+
+ /* Check whether the flag to allow silent storage attachment reconfiguration is set. */
+ strReconfig = getExtraData(Utf8Str("VBoxInternal2/SilentReconfigureWhilePaused"));
+ if ( mData->mMachineState == MachineState_Paused
+ && strReconfig == "1")
+ fSilent = true;
+
/* Check that the controller can do hotplugging if we detach the device while the VM is running. */
bool fHotplug = false;
- if (Global::IsOnlineOrTransient(mData->mMachineState))
+ if (!fSilent && Global::IsOnlineOrTransient(mData->mMachineState))
fHotplug = true;
if (fHotplug && !isControllerHotplugCapable(ctrlType))
@@ -4187,10 +4651,10 @@ STDMETHODIMP Machine::DetachDevice(IN_BSTR aControllerName, LONG aControllerPort
* The VM has to detach the device before we delete any implicit diffs.
* If this fails we can roll back without loosing data.
*/
- if (fHotplug)
+ if (fHotplug || fSilent)
{
alock.release();
- rc = onStorageDeviceChange(pAttach, TRUE /* aRemove */);
+ rc = onStorageDeviceChange(pAttach, TRUE /* aRemove */, fSilent);
alock.acquire();
}
if (FAILED(rc)) return rc;
@@ -4386,6 +4850,58 @@ STDMETHODIMP Machine::SetAutoDiscardForDevice(IN_BSTR aControllerName, LONG aCon
return S_OK;
}
+STDMETHODIMP Machine::SetHotPluggableForDevice(IN_BSTR aControllerName, LONG aControllerPort,
+ LONG aDevice, BOOL aHotPluggable)
+{
+ CheckComArgStrNotEmptyOrNull(aControllerName);
+
+ LogFlowThisFunc(("aControllerName=\"%ls\" aControllerPort=%d aDevice=%d aHotPluggable=%d\n",
+ aControllerName, aControllerPort, aDevice, aHotPluggable));
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ HRESULT rc = checkStateDependency(MutableStateDep);
+ if (FAILED(rc)) return rc;
+
+ AssertReturn(mData->mMachineState != MachineState_Saved, E_FAIL);
+
+ if (Global::IsOnlineOrTransient(mData->mMachineState))
+ return setError(VBOX_E_INVALID_VM_STATE,
+ tr("Invalid machine state: %s"),
+ Global::stringifyMachineState(mData->mMachineState));
+
+ MediumAttachment *pAttach = findAttachment(mMediaData->mAttachments,
+ aControllerName,
+ aControllerPort,
+ aDevice);
+ if (!pAttach)
+ return setError(VBOX_E_OBJECT_NOT_FOUND,
+ tr("No storage device attached to device slot %d on port %d of controller '%ls'"),
+ aDevice, aControllerPort, aControllerName);
+
+ /** @todo remove this blocker and add the missing code to support this
+ * flag properly in all code areas, with proper support checks below. */
+ return setError(VBOX_E_NOT_SUPPORTED,
+ tr("Controller '%ls' does not support changing the hot-pluggable device flag"),
+ aControllerName);
+
+ setModified(IsModified_Storage);
+ mMediaData.backup();
+
+ AutoWriteLock attLock(pAttach COMMA_LOCKVAL_SRC_POS);
+
+ if (pAttach->getType() == DeviceType_Floppy)
+ return setError(E_INVALIDARG,
+ tr("Setting the hot-pluggable device flag rejected as the device attached to device slot %d on port %d of controller '%ls' is a floppy drive"),
+ aDevice, aControllerPort, aControllerName);
+ pAttach->updateHotPluggable(!!aHotPluggable);
+
+ return S_OK;
+}
+
STDMETHODIMP Machine::SetNoBandwidthGroupForDevice(IN_BSTR aControllerName, LONG aControllerPort,
LONG aDevice)
{
@@ -4833,6 +5349,18 @@ STDMETHODIMP Machine::SetExtraData(IN_BSTR aKey, IN_BSTR aValue)
return S_OK;
}
+STDMETHODIMP Machine::SetSettingsFilePath(IN_BSTR aFilePath, IProgress **aProgress)
+{
+ CheckComArgStrNotEmptyOrNull(aFilePath);
+ CheckComArgOutPointerValid(aProgress);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ *aProgress = NULL;
+ ReturnComNotImplemented();
+}
+
STDMETHODIMP Machine::SaveSettings()
{
AutoCaller autoCaller(this);
@@ -5024,7 +5552,7 @@ struct Machine::DeleteTask
ComObjPtr<Progress> pProgress;
};
-STDMETHODIMP Machine::Delete(ComSafeArrayIn(IMedium*, aMedia), IProgress **aProgress)
+STDMETHODIMP Machine::DeleteConfig(ComSafeArrayIn(IMedium*, aMedia), IProgress **aProgress)
{
LogFlowFuncEnter();
@@ -5169,7 +5697,7 @@ HRESULT Machine::deleteTaskWorker(DeleteTask &task)
if (FAILED(rc)) throw rc;
rc = task.pProgress->WaitForAsyncProgressCompletion(pProgress2);
if (FAILED(rc)) throw rc;
- /* Check the result of the asynchrony process. */
+ /* Check the result of the asynchronous process. */
LONG iRc;
rc = pProgress2->COMGETTER(ResultCode)(&iRc);
if (FAILED(rc)) throw rc;
@@ -5177,6 +5705,15 @@ HRESULT Machine::deleteTaskWorker(DeleteTask &task)
* retrieve the error info from there, or it'll be lost. */
if (FAILED(iRc))
throw setError(ProgressErrorInfo(pProgress2));
+
+ /* Close the medium, deliberately without checking the return
+ * code, and without leaving any trace in the error info, as
+ * a failure here is a very minor issue, which shouldn't happen
+ * as above we even managed to delete the medium. */
+ {
+ ErrorInfoKeeper eik;
+ pMedium->Close();
+ }
}
setMachineState(oldState);
alock.acquire();
@@ -5292,7 +5829,7 @@ STDMETHODIMP Machine::FindSnapshot(IN_BSTR aNameOrId, ISnapshot **aSnapshot)
else
{
Guid uuid(aNameOrId);
- if (!uuid.isEmpty())
+ if (uuid.isValid())
rc = findSnapshotById(uuid, pSnapshot, true /* aSetError */);
else
rc = findSnapshotByName(Utf8Str(aNameOrId), pSnapshot, true /* aSetError */);
@@ -5441,21 +5978,17 @@ HRESULT Machine::getGuestPropertyFromService(IN_BSTR aName,
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
Utf8Str strName(aName);
- HWData::GuestPropertyList::const_iterator it;
+ HWData::GuestPropertyMap::const_iterator it = mHWData->mGuestProperties.find(strName);
- for (it = mHWData->mGuestProperties.begin();
- it != mHWData->mGuestProperties.end(); ++it)
+ if (it != mHWData->mGuestProperties.end())
{
- if (it->strName == strName)
- {
- char szFlags[MAX_FLAGS_LEN + 1];
- it->strValue.cloneTo(aValue);
- *aTimestamp = it->mTimestamp;
- writeFlags(it->mFlags, szFlags);
- Bstr(szFlags).cloneTo(aFlags);
- break;
- }
+ char szFlags[MAX_FLAGS_LEN + 1];
+ it->second.strValue.cloneTo(aValue);
+ *aTimestamp = it->second.mTimestamp;
+ writeFlags(it->second.mFlags, szFlags);
+ Bstr(szFlags).cloneTo(aFlags);
}
+
return S_OK;
}
@@ -5477,6 +6010,9 @@ HRESULT Machine::getGuestPropertyFromVM(IN_BSTR aName,
/* fail if we were called after #OnSessionEnd() is called. This is a
* silly race condition. */
+ /** @todo This code is bothering API clients (like python script clients) with
+ * the AccessGuestProperty call, creating unncessary IPC. Need to
+ * have a way of figuring out which kind of direct session it is... */
if (!directControl)
rc = E_ACCESSDENIED;
else
@@ -5536,9 +6072,6 @@ HRESULT Machine::setGuestPropertyToService(IN_BSTR aName, IN_BSTR aValue,
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
HRESULT rc = S_OK;
- HWData::GuestProperty property;
- property.mFlags = NILFLAG;
- bool found = false;
rc = checkStateDependency(MutableStateDep);
if (FAILED(rc)) return rc;
@@ -5548,64 +6081,59 @@ HRESULT Machine::setGuestPropertyToService(IN_BSTR aName, IN_BSTR aValue,
Utf8Str utf8Name(aName);
Utf8Str utf8Flags(aFlags);
uint32_t fFlags = NILFLAG;
- if ( (aFlags != NULL)
- && RT_FAILURE(validateFlags(utf8Flags.c_str(), &fFlags))
- )
+ if ( aFlags != NULL
+ && RT_FAILURE(validateFlags(utf8Flags.c_str(), &fFlags)))
return setError(E_INVALIDARG,
- tr("Invalid flag values: '%ls'"),
+ tr("Invalid guest property flag values: '%ls'"),
aFlags);
- /** @todo r=bird: see efficiency rant in PushGuestProperty. (Yeah, I
- * know, this is simple and do an OK job atm.) */
- HWData::GuestPropertyList::iterator it;
- for (it = mHWData->mGuestProperties.begin();
- it != mHWData->mGuestProperties.end(); ++it)
- if (it->strName == utf8Name)
- {
- property = *it;
- if (it->mFlags & (RDONLYHOST))
- rc = setError(E_ACCESSDENIED,
- tr("The property '%ls' cannot be changed by the host"),
- aName);
- else
- {
- setModified(IsModified_MachineData);
- mHWData.backup(); // @todo r=dj backup in a loop?!?
-
- /* The backup() operation invalidates our iterator, so
- * get a new one. */
- for (it = mHWData->mGuestProperties.begin();
- it->strName != utf8Name;
- ++it)
- ;
- mHWData->mGuestProperties.erase(it);
- }
- found = true;
- break;
- }
- if (found && SUCCEEDED(rc))
+ bool fDelete = !RT_VALID_PTR(aValue) || *(aValue) == '\0';
+ HWData::GuestPropertyMap::iterator it = mHWData->mGuestProperties.find(utf8Name);
+ if (it == mHWData->mGuestProperties.end())
{
- if (aValue)
+ if (!fDelete)
{
+ setModified(IsModified_MachineData);
+ mHWData.backupEx();
+
RTTIMESPEC time;
- property.strValue = aValue;
- property.mTimestamp = RTTimeSpecGetNano(RTTimeNow(&time));
- if (aFlags != NULL)
- property.mFlags = fFlags;
- mHWData->mGuestProperties.push_back(property);
+ HWData::GuestProperty prop;
+ prop.strValue = aValue;
+ prop.mTimestamp = RTTimeSpecGetNano(RTTimeNow(&time));
+ prop.mFlags = fFlags;
+ mHWData->mGuestProperties[Utf8Str(aName)] = prop;
}
}
- else if (SUCCEEDED(rc) && aValue)
+ else
{
- RTTIMESPEC time;
- setModified(IsModified_MachineData);
- mHWData.backup();
- property.strName = aName;
- property.strValue = aValue;
- property.mTimestamp = RTTimeSpecGetNano(RTTimeNow(&time));
- property.mFlags = fFlags;
- mHWData->mGuestProperties.push_back(property);
+ if (it->second.mFlags & (RDONLYHOST))
+ {
+ rc = setError(E_ACCESSDENIED,
+ tr("The property '%ls' cannot be changed by the host"),
+ aName);
+ }
+ else
+ {
+ setModified(IsModified_MachineData);
+ mHWData.backupEx();
+
+ /* The backupEx() operation invalidates our iterator,
+ * so get a new one. */
+ it = mHWData->mGuestProperties.find(utf8Name);
+ Assert(it != mHWData->mGuestProperties.end());
+
+ if (!fDelete)
+ {
+ RTTIMESPEC time;
+ it->second.strValue = aValue;
+ it->second.mTimestamp = RTTimeSpecGetNano(RTTimeNow(&time));
+ it->second.mFlags = fFlags;
+ }
+ else
+ mHWData->mGuestProperties.erase(it);
+ }
}
+
if ( SUCCEEDED(rc)
&& ( mHWData->mGuestPropertyNotificationPatterns.isEmpty()
|| RTStrSimplePatternMultiMatch(mHWData->mGuestPropertyNotificationPatterns.c_str(),
@@ -5616,8 +6144,8 @@ HRESULT Machine::setGuestPropertyToService(IN_BSTR aName, IN_BSTR aValue,
)
)
{
- /** @todo r=bird: Why aren't we leaving the lock here? The
- * same code in PushGuestProperty does... */
+ alock.release();
+
mParent->onGuestPropertyChange(mData->mUuid, aName,
aValue ? aValue : Bstr("").raw(),
aFlags ? aFlags : Bstr("").raw());
@@ -5651,8 +6179,7 @@ HRESULT Machine::setGuestPropertyToVM(IN_BSTR aName, IN_BSTR aValue,
if (!directControl)
rc = E_ACCESSDENIED;
else
- /** @todo Fix when adding DeleteGuestProperty(),
- see defect. */
+ /** @todo Fix when adding DeleteGuestProperty(), see defect. */
rc = directControl->AccessGuestProperty(aName, aValue, aFlags,
true /* isSetter */,
&dummy, &dummy64, &dummy);
@@ -5713,42 +6240,50 @@ HRESULT Machine::enumerateGuestPropertiesInService
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
Utf8Str strPatterns(aPatterns);
+ HWData::GuestPropertyMap propMap;
+
/*
* Look for matching patterns and build up a list.
*/
- HWData::GuestPropertyList propList;
- for (HWData::GuestPropertyList::iterator it = mHWData->mGuestProperties.begin();
- it != mHWData->mGuestProperties.end();
- ++it)
+ HWData::GuestPropertyMap::const_iterator it = mHWData->mGuestProperties.begin();
+ while (it != mHWData->mGuestProperties.end())
+ {
if ( strPatterns.isEmpty()
|| RTStrSimplePatternMultiMatch(strPatterns.c_str(),
RTSTR_MAX,
- it->strName.c_str(),
+ it->first.c_str(),
RTSTR_MAX,
NULL)
)
- propList.push_back(*it);
+ {
+ propMap.insert(*it);
+ }
+
+ it++;
+ }
+
+ alock.release();
/*
* And build up the arrays for returning the property information.
*/
- size_t cEntries = propList.size();
+ size_t cEntries = propMap.size();
SafeArray<BSTR> names(cEntries);
SafeArray<BSTR> values(cEntries);
SafeArray<LONG64> timestamps(cEntries);
SafeArray<BSTR> flags(cEntries);
size_t iProp = 0;
- for (HWData::GuestPropertyList::iterator it = propList.begin();
- it != propList.end();
- ++it)
+
+ it = propMap.begin();
+ while (it != propMap.end())
{
char szFlags[MAX_FLAGS_LEN + 1];
- it->strName.cloneTo(&names[iProp]);
- it->strValue.cloneTo(&values[iProp]);
- timestamps[iProp] = it->mTimestamp;
- writeFlags(it->mFlags, szFlags);
- Bstr(szFlags).cloneTo(&flags[iProp]);
- ++iProp;
+ it->first.cloneTo(&names[iProp]);
+ it->second.strValue.cloneTo(&values[iProp]);
+ timestamps[iProp] = it->second.mTimestamp;
+ writeFlags(it->second.mFlags, szFlags);
+ Bstr(szFlags).cloneTo(&flags[iProp++]);
+ it++;
}
names.detachTo(ComSafeArrayOutArg(aNames));
values.detachTo(ComSafeArrayOutArg(aValues));
@@ -6083,6 +6618,132 @@ STDMETHODIMP Machine::RemoveStorageController(IN_BSTR aName)
return S_OK;
}
+STDMETHODIMP Machine::AddUSBController(IN_BSTR aName, USBControllerType_T aType,
+ IUSBController **controller)
+{
+ if ( (aType <= USBControllerType_Null)
+ || (aType >= USBControllerType_Last))
+ return setError(E_INVALIDARG,
+ tr("Invalid USB controller type: %d"),
+ aType);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ HRESULT rc = checkStateDependency(MutableStateDep);
+ if (FAILED(rc)) return rc;
+
+ /* try to find one with the same type first. */
+ ComObjPtr<USBController> ctrl;
+
+ rc = getUSBControllerByName(aName, ctrl, false /* aSetError */);
+ if (SUCCEEDED(rc))
+ return setError(VBOX_E_OBJECT_IN_USE,
+ tr("USB controller named '%ls' already exists"),
+ aName);
+
+ /* Check that we don't exceed the maximum number of USB controllers for the given type. */
+ ULONG maxInstances;
+ rc = mParent->getSystemProperties()->GetMaxInstancesOfUSBControllerType(mHWData->mChipsetType, aType, &maxInstances);
+ if (FAILED(rc))
+ return rc;
+
+ ULONG cInstances = getUSBControllerCountByType(aType);
+ if (cInstances >= maxInstances)
+ return setError(E_INVALIDARG,
+ tr("Too many USB controllers of this type"));
+
+ ctrl.createObject();
+
+ rc = ctrl->init(this, aName, aType);
+ if (FAILED(rc)) return rc;
+
+ setModified(IsModified_USB);
+ mUSBControllers.backup();
+ mUSBControllers->push_back(ctrl);
+
+ ctrl.queryInterfaceTo(controller);
+
+ /* inform the direct session if any */
+ alock.release();
+ onUSBControllerChange();
+
+ return S_OK;
+}
+
+STDMETHODIMP Machine::GetUSBControllerByName(IN_BSTR aName, IUSBController **aUSBController)
+{
+ CheckComArgStrNotEmptyOrNull(aName);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ ComObjPtr<USBController> ctrl;
+
+ HRESULT rc = getUSBControllerByName(aName, ctrl, true /* aSetError */);
+ if (SUCCEEDED(rc))
+ ctrl.queryInterfaceTo(aUSBController);
+
+ return rc;
+}
+
+STDMETHODIMP Machine::GetUSBControllerCountByType(USBControllerType_T aType,
+ ULONG *aControllers)
+{
+ CheckComArgOutPointerValid(aControllers);
+
+ if ( (aType <= USBControllerType_Null)
+ || (aType >= USBControllerType_Last))
+ return setError(E_INVALIDARG,
+ tr("Invalid USB controller type: %d"),
+ aType);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ ComObjPtr<USBController> ctrl;
+
+ *aControllers = getUSBControllerCountByType(aType);
+
+ return S_OK;
+}
+
+STDMETHODIMP Machine::RemoveUSBController(IN_BSTR aName)
+{
+ CheckComArgStrNotEmptyOrNull(aName);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ HRESULT rc = checkStateDependency(MutableStateDep);
+ if (FAILED(rc)) return rc;
+
+ ComObjPtr<USBController> ctrl;
+ rc = getUSBControllerByName(aName, ctrl, true /* aSetError */);
+ if (FAILED(rc)) return rc;
+
+ setModified(IsModified_USB);
+ mUSBControllers.backup();
+
+ ctrl->unshare();
+
+ mUSBControllers->remove(ctrl);
+
+ /* inform the direct session if any */
+ alock.release();
+ onUSBControllerChange();
+
+ return S_OK;
+}
+
STDMETHODIMP Machine::QuerySavedGuestScreenInfo(ULONG uScreenId,
ULONG *puOriginX,
ULONG *puOriginY,
@@ -6397,7 +7058,7 @@ STDMETHODIMP Machine::HotPlugCPU(ULONG aCpu)
mHWData.backup();
mHWData->mCPUAttached[aCpu] = true;
- /* Save settings if online */
+ /** Save settings if online - @todo why is this required? -- @bugref{6818} */
if (Global::IsOnline(mData->mMachineState))
saveSettings(NULL);
@@ -6438,7 +7099,7 @@ STDMETHODIMP Machine::HotUnplugCPU(ULONG aCpu)
mHWData.backup();
mHWData->mCPUAttached[aCpu] = false;
- /* Save settings if online */
+ /** Save settings if online - @todo why is this required? -- @bugref{6818} */
if (Global::IsOnline(mData->mMachineState))
saveSettings(NULL);
@@ -6934,6 +7595,92 @@ STDMETHODIMP Machine::COMSETTER(AutostopType)(AutostopType_T enmAutostopType)
return hrc;
}
+STDMETHODIMP Machine::COMGETTER(DefaultFrontend)(BSTR *aDefaultFrontend)
+{
+ CheckComArgOutPointerValid(aDefaultFrontend);
+ AutoCaller autoCaller(this);
+ HRESULT hrc = autoCaller.rc();
+ if (SUCCEEDED(hrc))
+ {
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+ mHWData->mDefaultFrontend.cloneTo(aDefaultFrontend);
+ }
+ return hrc;
+}
+
+STDMETHODIMP Machine::COMSETTER(DefaultFrontend)(IN_BSTR aDefaultFrontend)
+{
+ CheckComArgStr(aDefaultFrontend);
+ AutoCaller autoCaller(this);
+ HRESULT hrc = autoCaller.rc();
+ if (SUCCEEDED(hrc))
+ {
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+ hrc = checkStateDependency(MutableOrSavedStateDep);
+ if (SUCCEEDED(hrc))
+ {
+ hrc = mHWData.backupEx();
+ if (SUCCEEDED(hrc))
+ {
+ setModified(IsModified_MachineData);
+ mHWData->mDefaultFrontend = aDefaultFrontend;
+ }
+ }
+ }
+ return hrc;
+}
+
+STDMETHODIMP Machine::COMGETTER(Icon)(ComSafeArrayOut(BYTE, aIcon))
+{
+ CheckComArgSafeArrayNotNull(aIcon);
+ CheckComArgOutSafeArrayPointerValid(aIcon);
+ AutoCaller autoCaller(this);
+ HRESULT hrc = autoCaller.rc();
+ if (SUCCEEDED(hrc))
+ {
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+ com::SafeArray<BYTE> icon(mUserData->mIcon.size());
+ memcpy(icon.raw(), &mUserData->mIcon[0], mUserData->mIcon.size());
+ icon.detachTo(ComSafeArrayOutArg(aIcon));
+ }
+ return hrc;
+}
+
+STDMETHODIMP Machine::COMSETTER(Icon)(ComSafeArrayIn(BYTE, aIcon))
+{
+ CheckComArgSafeArrayNotNull(aIcon);
+ AutoCaller autoCaller(this);
+ HRESULT hrc = autoCaller.rc();
+ if (SUCCEEDED(hrc))
+ {
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+ hrc = checkStateDependency(MutableOrSavedStateDep);
+ if (SUCCEEDED(hrc))
+ {
+ setModified(IsModified_MachineData);
+ mUserData.backup();
+ com::SafeArray<BYTE> icon(ComSafeArrayInArg(aIcon));
+ mUserData->mIcon.resize(icon.size());
+ memcpy(&mUserData->mIcon[0], icon.raw(), mUserData->mIcon.size());
+ }
+ }
+ return hrc;
+}
+
+STDMETHODIMP Machine::COMGETTER(USBProxyAvailable)(BOOL *aAvailable)
+{
+ CheckComArgOutPointerValid(aAvailable);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+#ifdef VBOX_WITH_USB
+ *aAvailable = true;
+#else
+ *aAvailable = false;
+#endif
+ return S_OK;
+}
STDMETHODIMP Machine::CloneTo(IMachine *pTarget, CloneMode_T mode, ComSafeArrayIn(CloneOptions_T, options), IProgress **pProgress)
{
@@ -7180,11 +7927,39 @@ void Machine::composeSavedStateFilename(Utf8Str &strStateFilePath)
}
/**
+ * Returns the full path to the default video capture file.
+ */
+void Machine::getDefaultVideoCaptureFile(Utf8Str &strFile)
+{
+ AutoCaller autoCaller(this);
+ AssertComRCReturnVoid(autoCaller.rc());
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ strFile = mData->m_strConfigFileFull; // path/to/machinesfolder/vmname/vmname.vbox
+ strFile.stripExt(); // path/to/machinesfolder/vmname/vmname
+ strFile.append(".webm"); // path/to/machinesfolder/vmname/vmname.webm
+}
+
+/**
+ * Returns whether at least one USB controller is present for the VM.
+ */
+bool Machine::isUSBControllerPresent()
+{
+ AutoCaller autoCaller(this);
+ AssertComRCReturn(autoCaller.rc(), false);
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ return (mUSBControllers->size() > 0);
+}
+
+/**
* @note Locks this object for writing, calls the client process
* (inside the lock).
*/
HRESULT Machine::launchVMProcess(IInternalSessionControl *aControl,
- const Utf8Str &strType,
+ const Utf8Str &strFrontend,
const Utf8Str &strEnvironment,
ProgressProxy *aProgress)
{
@@ -7192,6 +7967,7 @@ HRESULT Machine::launchVMProcess(IInternalSessionControl *aControl,
AssertReturn(aControl, E_FAIL);
AssertReturn(aProgress, E_FAIL);
+ AssertReturn(!strFrontend.isEmpty(), E_FAIL);
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
@@ -7222,7 +7998,7 @@ HRESULT Machine::launchVMProcess(IInternalSessionControl *aControl,
szPath[sz++] = RTPATH_DELIMITER;
szPath[sz] = 0;
char *cmd = szPath + sz;
- sz = RTPATH_MAX - sz;
+ sz = sizeof(szPath) - sz;
int vrc = VINF_SUCCESS;
RTPROCESS pid = NIL_RTPROCESS;
@@ -7278,16 +8054,44 @@ HRESULT Machine::launchVMProcess(IInternalSessionControl *aControl,
RTStrFree(newEnvStr);
}
- /* Qt is default */
#ifdef VBOX_WITH_QTGUI
- if (strType == "gui" || strType == "GUI/Qt")
+ if (strFrontend == "gui" || strFrontend == "GUI/Qt")
{
# ifdef RT_OS_DARWIN /* Avoid Launch Services confusing this with the selector by using a helper app. */
- const char VirtualBox_exe[] = "../Resources/VirtualBoxVM.app/Contents/MacOS/VirtualBoxVM";
+ /* Modify the base path so that we don't need to use ".." below. */
+ RTPathStripTrailingSlash(szPath);
+ RTPathStripFilename(szPath);
+ sz = strlen(szPath);
+ cmd = szPath + sz;
+ sz = sizeof(szPath) - sz;
+
+#define OSX_APP_NAME "VirtualBoxVM"
+#define OSX_APP_PATH_FMT "/Resources/%s.app/Contents/MacOS/VirtualBoxVM"
+
+ Utf8Str strAppOverride = getExtraData(Utf8Str("VBoxInternal2/VirtualBoxVMAppOverride"));
+ if ( strAppOverride.contains(".")
+ || strAppOverride.contains("/")
+ || strAppOverride.contains("\\")
+ || strAppOverride.contains(":"))
+ strAppOverride.setNull();
+ Utf8Str strAppPath;
+ if (!strAppOverride.isEmpty())
+ {
+ strAppPath = Utf8StrFmt(OSX_APP_PATH_FMT, strAppOverride.c_str());
+ Utf8Str strFullPath(szPath);
+ strFullPath.append(strAppPath);
+ /* there is a race, but people using this deserve the failure */
+ if (!RTFileExists(strFullPath.c_str()))
+ strAppOverride.setNull();
+ }
+ if (strAppOverride.isEmpty())
+ strAppPath = Utf8StrFmt(OSX_APP_PATH_FMT, OSX_APP_NAME);
+ const char *VirtualBox_exe = strAppPath.c_str();
+ AssertReturn(sz >= strlen(VirtualBox_exe), E_UNEXPECTED);
# else
const char VirtualBox_exe[] = "VirtualBox" HOSTSUFF_EXE;
-# endif
Assert(sz >= sizeof(VirtualBox_exe));
+# endif
strcpy(cmd, VirtualBox_exe);
Utf8Str idStr = mData->mUuid.toString();
@@ -7302,7 +8106,7 @@ HRESULT Machine::launchVMProcess(IInternalSessionControl *aControl,
else
#ifdef VBOX_WITH_VBOXSDL
- if (strType == "sdl" || strType == "GUI/SDL")
+ if (strFrontend == "sdl" || strFrontend == "GUI/SDL")
{
const char VBoxSDL_exe[] = "VBoxSDL" HOSTSUFF_EXE;
Assert(sz >= sizeof(VBoxSDL_exe));
@@ -7320,9 +8124,9 @@ HRESULT Machine::launchVMProcess(IInternalSessionControl *aControl,
else
#ifdef VBOX_WITH_HEADLESS
- if ( strType == "headless"
- || strType == "capture"
- || strType == "vrdp" /* Deprecated. Same as headless. */
+ if ( strFrontend == "headless"
+ || strFrontend == "capture"
+ || strFrontend == "vrdp" /* Deprecated. Same as headless. */
)
{
/* On pre-4.0 the "headless" type was used for passing "--vrdp off" to VBoxHeadless to let it work in OSE,
@@ -7343,7 +8147,7 @@ HRESULT Machine::launchVMProcess(IInternalSessionControl *aControl,
"--vrde", "config",
0, /* For "--capture". */
0 };
- if (strType == "capture")
+ if (strFrontend == "capture")
{
unsigned pos = RT_ELEMENTS(args) - 2;
args[pos] = "--capture";
@@ -7364,8 +8168,8 @@ HRESULT Machine::launchVMProcess(IInternalSessionControl *aControl,
{
RTEnvDestroy(env);
return setError(E_INVALIDARG,
- tr("Invalid session type: '%s'"),
- strType.c_str());
+ tr("Invalid frontend name: '%s'"),
+ strFrontend.c_str());
}
RTEnvDestroy(env);
@@ -7382,22 +8186,28 @@ HRESULT Machine::launchVMProcess(IInternalSessionControl *aControl,
* because it doesn't need to call us back if called with a NULL argument.
* Releasing the lock here is dangerous because we didn't prepare the
* launch data yet, but the client we've just started may happen to be
- * too fast and call openSession() that will fail (because of PID, etc.),
+ * too fast and call LockMachine() that will fail (because of PID, etc.),
* so that the Machine will never get out of the Spawning session state.
*/
/* inform the session that it will be a remote one */
LogFlowThisFunc(("Calling AssignMachine (NULL)...\n"));
- HRESULT rc = aControl->AssignMachine(NULL, LockType_Write);
+#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER
+ HRESULT rc = aControl->AssignMachine(NULL, LockType_Write, Bstr::Empty.raw());
+#else /* VBOX_WITH_GENERIC_SESSION_WATCHER */
+ HRESULT rc = aControl->AssignMachine(NULL, LockType_Write, NULL);
+#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */
LogFlowThisFunc(("AssignMachine (NULL) returned %08X\n", rc));
if (FAILED(rc))
{
/* restore the session state */
mData->mSession.mState = SessionState_Unlocked;
+ alock.release();
+ mParent->addProcessToReap(pid);
/* The failure may occur w/o any error info (from RPC), so provide one */
return setError(VBOX_E_VM_ERROR,
- tr("Failed to assign the machine to the session (%Rrc)"), rc);
+ tr("Failed to assign the machine to the session (%Rhrc)"), rc);
}
/* attach launch data to the machine */
@@ -7406,40 +8216,32 @@ HRESULT Machine::launchVMProcess(IInternalSessionControl *aControl,
mData->mSession.mProgress = aProgress;
mData->mSession.mPID = pid;
mData->mSession.mState = SessionState_Spawning;
- mData->mSession.mType = strType;
+ mData->mSession.mType = strFrontend;
+
+ alock.release();
+ mParent->addProcessToReap(pid);
LogFlowThisFuncLeave();
return S_OK;
}
/**
- * Returns @c true if the given machine has an open direct session and returns
- * the session machine instance and additional session data (on some platforms)
- * if so.
+ * Returns @c true if the given session machine instance has an open direct
+ * session (and optionally also for direct sessions which are closing) and
+ * returns the session control machine instance if so.
*
* Note that when the method returns @c false, the arguments remain unchanged.
*
- * @param aMachine Session machine object.
- * @param aControl Direct session control object (optional).
- * @param aIPCSem Mutex IPC semaphore handle for this machine (optional).
+ * @param aMachine Session machine object.
+ * @param aControl Direct session control object (optional).
+ * @param aAllowClosing If true then additionally a session which is currently
+ * being closed will also be allowed.
*
* @note locks this object for reading.
*/
-#if defined(RT_OS_WINDOWS)
-bool Machine::isSessionOpen(ComObjPtr<SessionMachine> &aMachine,
- ComPtr<IInternalSessionControl> *aControl /*= NULL*/,
- HANDLE *aIPCSem /*= NULL*/,
- bool aAllowClosing /*= false*/)
-#elif defined(RT_OS_OS2)
-bool Machine::isSessionOpen(ComObjPtr<SessionMachine> &aMachine,
- ComPtr<IInternalSessionControl> *aControl /*= NULL*/,
- HMTX *aIPCSem /*= NULL*/,
- bool aAllowClosing /*= false*/)
-#else
bool Machine::isSessionOpen(ComObjPtr<SessionMachine> &aMachine,
ComPtr<IInternalSessionControl> *aControl /*= NULL*/,
bool aAllowClosing /*= false*/)
-#endif
{
AutoLimitedCaller autoCaller(this);
AssertComRCReturn(autoCaller.rc(), false);
@@ -7461,11 +8263,6 @@ bool Machine::isSessionOpen(ComObjPtr<SessionMachine> &aMachine,
if (aControl != NULL)
*aControl = mData->mSession.mDirectControl;
-#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
- /* Additional session data */
- if (aIPCSem != NULL)
- *aIPCSem = aMachine->mIPCSem;
-#endif
return true;
}
@@ -7473,20 +8270,11 @@ bool Machine::isSessionOpen(ComObjPtr<SessionMachine> &aMachine,
}
/**
- * Returns @c true if the given machine has an spawning direct session and
- * returns and additional session data (on some platforms) if so.
- *
- * Note that when the method returns @c false, the arguments remain unchanged.
- *
- * @param aPID PID of the spawned direct session process.
+ * Returns @c true if the given machine has an spawning direct session.
*
* @note locks this object for reading.
*/
-#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
-bool Machine::isSessionSpawning(RTPROCESS *aPID /*= NULL*/)
-#else
bool Machine::isSessionSpawning()
-#endif
{
AutoLimitedCaller autoCaller(this);
AssertComRCReturn(autoCaller.rc(), false);
@@ -7498,17 +8286,7 @@ bool Machine::isSessionSpawning()
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
if (mData->mSession.mState == SessionState_Spawning)
- {
-#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
- /* Additional session data */
- if (aPID != NULL)
- {
- AssertReturn(mData->mSession.mPID != NIL_RTPROCESS, false);
- *aPID = mData->mSession.mPID;
- }
-#endif
return true;
- }
return false;
}
@@ -7537,8 +8315,7 @@ bool Machine::checkForSpawnFailure()
return true;
}
- /* VirtualBox::addProcessToReap() needs a write lock */
- AutoMultiWriteLock2 alock(mParent, this COMMA_LOCKVAL_SRC_POS);
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
if (mData->mSession.mState != SessionState_Spawning)
{
@@ -7549,22 +8326,12 @@ bool Machine::checkForSpawnFailure()
HRESULT rc = S_OK;
-#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
-
- /* the process was already unexpectedly terminated, we just need to set an
- * error and finalize session spawning */
- rc = setError(E_FAIL,
- tr("The virtual machine '%s' has terminated unexpectedly during startup"),
- getName().c_str());
-#else
-
/* PID not yet initialized, skip check. */
if (mData->mSession.mPID == NIL_RTPROCESS)
return false;
RTPROCSTATUS status;
- int vrc = ::RTProcWait(mData->mSession.mPID, RTPROCWAIT_FLAGS_NOBLOCK,
- &status);
+ int vrc = RTProcWait(mData->mSession.mPID, RTPROCWAIT_FLAGS_NOBLOCK, &status);
if (vrc != VERR_PROCESS_RUNNING)
{
@@ -7583,16 +8350,14 @@ bool Machine::checkForSpawnFailure()
else
rc = setError(E_FAIL,
tr("The virtual machine '%s' has terminated unexpectedly during startup (%Rrc)"),
- getName().c_str(), rc);
+ getName().c_str(), vrc);
}
-#endif
-
if (FAILED(rc))
{
/* Close the remote session, remove the remote control from the list
* and reset session state to Closed (@note keep the code in sync with
- * the relevant part in checkForSpawnFailure()). */
+ * the relevant part in LockMachine()). */
Assert(mData->mSession.mRemoteControls.size() == 1);
if (mData->mSession.mRemoteControls.size() == 1)
@@ -7611,7 +8376,6 @@ bool Machine::checkForSpawnFailure()
mData->mSession.mProgress.setNull();
}
- mParent->addProcessToReap(mData->mSession.mPID);
mData->mSession.mPID = NIL_RTPROCESS;
mParent->onSessionStateChange(mData->mUuid, SessionState_Unlocked);
@@ -7771,6 +8535,21 @@ void Machine::releaseStateDependency()
}
}
+Utf8Str Machine::getExtraData(const Utf8Str &strKey)
+{
+ /* start with nothing found */
+ Utf8Str strResult("");
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ settings::StringsMap::const_iterator it = mData->pMachineConfigFile->mapExtraDataItems.find(strKey);
+ if (it != mData->pMachineConfigFile->mapExtraDataItems.end())
+ // found:
+ strResult = it->second; // source is a Utf8Str
+
+ return strResult;
+}
+
// protected methods
/////////////////////////////////////////////////////////////////////////////
@@ -7894,6 +8673,7 @@ HRESULT Machine::initDataAndChildObjects()
mHWData.allocate();
mMediaData.allocate();
mStorageControllers.allocate();
+ mUSBControllers.allocate();
/* initialize mOSTypeId */
mUserData->s.strOsType = mParent->getUnknownOSType()->id();
@@ -7924,9 +8704,9 @@ HRESULT Machine::initDataAndChildObjects()
unconst(mAudioAdapter).createObject();
mAudioAdapter->init(this);
- /* create the USB controller object (always present, default is disabled) */
- unconst(mUSBController).createObject();
- mUSBController->init(this);
+ /* create the USB device filters object (always present) */
+ unconst(mUSBDeviceFilters).createObject();
+ mUSBDeviceFilters->init(this);
/* create associated network adapter objects */
mNetworkAdapters.resize(Global::getMaxNetworkAdapters(mHWData->mChipsetType));
@@ -7975,10 +8755,10 @@ void Machine::uninitDataAndChildObjects()
}
}
- if (mUSBController)
+ if (mUSBDeviceFilters)
{
- mUSBController->uninit();
- unconst(mUSBController).setNull();
+ mUSBDeviceFilters->uninit();
+ unconst(mUSBDeviceFilters).setNull();
}
if (mAudioAdapter)
@@ -8017,13 +8797,13 @@ void Machine::uninitDataAndChildObjects()
unconst(mBIOSSettings).setNull();
}
- /* Deassociate hard disks (only when a real Machine or a SnapshotMachine
+ /* Deassociate media (only when a real Machine or a SnapshotMachine
* instance is uninitialized; SessionMachine instances refer to real
- * Machine hard disks). This is necessary for a clean re-initialization of
+ * Machine media). This is necessary for a clean re-initialization of
* the VM after successfully re-checking the accessibility state. Note
* that in case of normal Machine or SnapshotMachine uninitialization (as
- * a result of unregistering or deleting the snapshot), outdated hard
- * disk attachments will already be uninitialized and deleted, so this
+ * a result of unregistering or deleting the snapshot), outdated media
+ * attachments will already be uninitialized and deleted, so this
* code will not affect them. */
if ( !!mMediaData
&& (!isSessionMachine())
@@ -8033,10 +8813,10 @@ void Machine::uninitDataAndChildObjects()
it != mMediaData->mAttachments.end();
++it)
{
- ComObjPtr<Medium> hd = (*it)->getMedium();
- if (hd.isNull())
+ ComObjPtr<Medium> pMedium = (*it)->getMedium();
+ if (pMedium.isNull())
continue;
- HRESULT rc = hd->removeBackReference(mData->mUuid, getSnapshotId());
+ HRESULT rc = pMedium->removeBackReference(mData->mUuid, getSnapshotId());
AssertComRC(rc);
}
}
@@ -8061,6 +8841,7 @@ void Machine::uninitDataAndChildObjects()
* since it may be still in use) */
mMediaData.free();
mStorageControllers.free();
+ mUSBControllers.free();
mHWData.free();
mUserData.free();
mSSData.free();
@@ -8228,9 +9009,28 @@ HRESULT Machine::loadMachineDataFromSettings(const settings::MachineConfigFile &
// copy name, description, OS type, teleporter, UTC etc.
mUserData->s = config.machineUserData;
+ // Decode the Icon overide data from config userdata and set onto Machine.
+ #define DECODE_STR_MAX _1M
+ const char* pszStr = config.machineUserData.ovIcon.c_str();
+ ssize_t cbOut = RTBase64DecodedSize(pszStr, NULL);
+ if (cbOut > DECODE_STR_MAX)
+ return setError(E_FAIL,
+ tr("Icon Data too long.'%d' > '%d'"),
+ cbOut,
+ DECODE_STR_MAX);
+ com::SafeArray<BYTE> iconByte(cbOut);
+ HRESULT rc = RTBase64Decode(pszStr, iconByte.raw(), cbOut, NULL, NULL);
+ if (FAILED(rc))
+ return setError(E_FAIL,
+ tr("Failure to Decode Icon Data. '%s' (%d)"),
+ pszStr,
+ rc);
+ mUserData->mIcon.resize(iconByte.size());
+ memcpy(&mUserData->mIcon[0], iconByte.raw(), mUserData->mIcon.size());
+
// look up the object by Id to check it is valid
ComPtr<IGuestOSType> guestOSType;
- HRESULT rc = mParent->GetGuestOSType(Bstr(mUserData->s.strOsType).raw(),
+ rc = mParent->GetGuestOSType(Bstr(mUserData->s.strOsType).raw(),
guestOSType.asOutParam());
if (FAILED(rc)) return rc;
@@ -8435,14 +9235,15 @@ HRESULT Machine::loadHardware(const settings::Hardware &data, const settings::De
mHWData->mHardwareUUID = data.uuid;
mHWData->mHWVirtExEnabled = data.fHardwareVirt;
- mHWData->mHWVirtExExclusive = data.fHardwareVirtExclusive;
mHWData->mHWVirtExNestedPagingEnabled = data.fNestedPaging;
mHWData->mHWVirtExLargePagesEnabled = data.fLargePages;
mHWData->mHWVirtExVPIDEnabled = data.fVPID;
+ mHWData->mHWVirtExUXEnabled = data.fUnrestrictedExecution;
mHWData->mHWVirtExForceEnabled = data.fHardwareVirtForce;
mHWData->mPAEEnabled = data.fPAE;
mHWData->mSyntheticCpu = data.fSyntheticCpu;
-
+ mHWData->mLongMode = data.enmLongMode;
+ mHWData->mTripleFaultReset = data.fTripleFaultReset;
mHWData->mCPUCount = data.cCPUs;
mHWData->mCPUHotPlugEnabled = data.fCpuHotPlug;
mHWData->mCpuExecutionCap = data.ulCpuExecutionCap;
@@ -8518,6 +9319,7 @@ HRESULT Machine::loadHardware(const settings::Hardware &data, const settings::De
mHWData->mBootOrder[i] = it->second;
}
+ mHWData->mGraphicsControllerType = data.graphicsControllerType;
mHWData->mVRAMSize = data.ulVRAMSizeMB;
mHWData->mMonitorCount = data.cMonitors;
mHWData->mAccelerate3DEnabled = data.fAccelerate3D;
@@ -8525,7 +9327,15 @@ HRESULT Machine::loadHardware(const settings::Hardware &data, const settings::De
mHWData->mVideoCaptureWidth = data.ulVideoCaptureHorzRes;
mHWData->mVideoCaptureHeight = data.ulVideoCaptureVertRes;
mHWData->mVideoCaptureEnabled = data.fVideoCaptureEnabled;
- mHWData->mVideoCaptureFile = data.strVideoCaptureFile;
+ for (unsigned i = 0; i < RT_ELEMENTS(mHWData->maVideoCaptureScreens); i++)
+ mHWData->maVideoCaptureScreens[i] = ASMBitTest(&data.u64VideoCaptureScreens, i);
+ AssertCompile(RT_ELEMENTS(mHWData->maVideoCaptureScreens) == sizeof(data.u64VideoCaptureScreens) * 8);
+ mHWData->mVideoCaptureRate = data.ulVideoCaptureRate;
+ mHWData->mVideoCaptureFPS = data.ulVideoCaptureFPS;
+ if (!data.strVideoCaptureFile.isEmpty())
+ calculateFullPath(data.strVideoCaptureFile, mHWData->mVideoCaptureFile);
+ else
+ mHWData->mVideoCaptureFile.setNull();
mHWData->mFirmwareType = data.firmwareType;
mHWData->mPointingHIDType = data.pointingHIDType;
mHWData->mKeyboardHIDType = data.keyboardHIDType;
@@ -8545,8 +9355,21 @@ HRESULT Machine::loadHardware(const settings::Hardware &data, const settings::De
rc = mBandwidthControl->loadSettings(data.ioSettings);
if (FAILED(rc)) return rc;
- /* USB Controller */
- rc = mUSBController->loadSettings(data.usbController);
+ /* Shared folders */
+ for (settings::USBControllerList::const_iterator it = data.usbSettings.llUSBControllers.begin();
+ it != data.usbSettings.llUSBControllers.end();
+ ++it)
+ {
+ const settings::USBController &settingsCtrl = *it;
+ ComObjPtr<USBController> newCtrl;
+
+ newCtrl.createObject();
+ newCtrl->init(this, settingsCtrl.strName, settingsCtrl.enmType);
+ mUSBControllers->push_back(newCtrl);
+ }
+
+ /* USB device filters */
+ rc = mUSBDeviceFilters->loadSettings(data.usbSettings);
if (FAILED(rc)) return rc;
// network adapters
@@ -8671,8 +9494,8 @@ HRESULT Machine::loadHardware(const settings::Hardware &data, const settings::De
const settings::GuestProperty &prop = *it;
uint32_t fFlags = guestProp::NILFLAG;
guestProp::validateFlags(prop.strFlags.c_str(), &fFlags);
- HWData::GuestProperty property = { prop.strName, prop.strValue, (LONG64) prop.timestamp, fFlags };
- mHWData->mGuestProperties.push_back(property);
+ HWData::GuestProperty property = { prop.strValue, (LONG64) prop.timestamp, fFlags };
+ mHWData->mGuestProperties[prop.strName] = property;
}
mHWData->mGuestPropertyNotificationPatterns = data.strNotificationPatterns;
@@ -8683,6 +9506,9 @@ HRESULT Machine::loadHardware(const settings::Hardware &data, const settings::De
return rc;
mHWData->mAutostart = *pAutostart;
+
+ /* default frontend */
+ mHWData->mDefaultFrontend = data.strDefaultFrontend;
}
catch(std::bad_alloc &)
{
@@ -8973,6 +9799,8 @@ HRESULT Machine::loadStorageDevices(StorageController *aStorageController,
dev.fTempEject,
dev.fNonRotational,
dev.fDiscard,
+ /// @todo load setting once the hot-pluggable flag works
+ false /*dev.fHotPluggable*/,
pBwGroup.isNull() ? Utf8Str::Empty : pBwGroup->getName());
if (FAILED(rc)) break;
@@ -9028,7 +9856,7 @@ HRESULT Machine::findSnapshotById(const Guid &aId,
return E_FAIL;
}
- if (aId.isEmpty())
+ if (aId.isZero())
aSnapshot = mData->mFirstSnapshot;
else
aSnapshot = mData->mFirstSnapshot->findChildOrSelf(aId.ref());
@@ -9112,6 +9940,57 @@ HRESULT Machine::getStorageControllerByName(const Utf8Str &aName,
return VBOX_E_OBJECT_NOT_FOUND;
}
+/**
+ * Returns a USB controller object with the given name.
+ *
+ * @param aName USB controller name to find
+ * @param aUSBController where to return the found USB controller
+ * @param aSetError true to set extended error info on failure
+ */
+HRESULT Machine::getUSBControllerByName(const Utf8Str &aName,
+ ComObjPtr<USBController> &aUSBController,
+ bool aSetError /* = false */)
+{
+ AssertReturn(!aName.isEmpty(), E_INVALIDARG);
+
+ for (USBControllerList::const_iterator it = mUSBControllers->begin();
+ it != mUSBControllers->end();
+ ++it)
+ {
+ if ((*it)->getName() == aName)
+ {
+ aUSBController = (*it);
+ return S_OK;
+ }
+ }
+
+ if (aSetError)
+ return setError(VBOX_E_OBJECT_NOT_FOUND,
+ tr("Could not find a storage controller named '%s'"),
+ aName.c_str());
+ return VBOX_E_OBJECT_NOT_FOUND;
+}
+
+/**
+ * Returns the number of USB controller instance of the given type.
+ *
+ * @param enmType USB controller type.
+ */
+ULONG Machine::getUSBControllerCountByType(USBControllerType_T enmType)
+{
+ ULONG cCtrls = 0;
+
+ for (USBControllerList::const_iterator it = mUSBControllers->begin();
+ it != mUSBControllers->end();
+ ++it)
+ {
+ if ((*it)->getControllerType() == enmType)
+ cCtrls++;
+ }
+
+ return cCtrls;
+}
+
HRESULT Machine::getMediumAttachmentsOfController(CBSTR aName,
MediaData::AttachmentList &atts)
{
@@ -9534,6 +10413,26 @@ void Machine::copyMachineDataToSettings(settings::MachineConfigFile &config)
// copy name, description, OS type, teleport, UTC etc.
config.machineUserData = mUserData->s;
+ // Encode the Icon Override data from Machine and store on config userdata.
+ com::SafeArray<BYTE> iconByte;
+ COMGETTER(Icon)(ComSafeArrayAsOutParam(iconByte));
+ ssize_t cbData = iconByte.size();
+ if (cbData > 0)
+ {
+ ssize_t cchOut = RTBase64EncodedLength(cbData);
+ Utf8Str strIconData;
+ strIconData.reserve(cchOut+1);
+ int vrc = RTBase64Encode(iconByte.raw(), cbData,
+ strIconData.mutableRaw(), strIconData.capacity(),
+ NULL);
+ if (RT_FAILURE(vrc))
+ throw setError(E_FAIL, tr("Failure to Encode Icon Data. '%s' (%Rrc)"), strIconData.mutableRaw(), vrc);
+ strIconData.jolt();
+ config.machineUserData.ovIcon = strIconData;
+ }
+ else
+ config.machineUserData.ovIcon.setNull();
+
if ( mData->mMachineState == MachineState_Saved
|| mData->mMachineState == MachineState_Restoring
// when deleting a snapshot we may or may not have a saved state in the current state,
@@ -9662,13 +10561,15 @@ HRESULT Machine::saveHardware(settings::Hardware &data, settings::Debugging *pDb
// CPU
data.fHardwareVirt = !!mHWData->mHWVirtExEnabled;
- data.fHardwareVirtExclusive = !!mHWData->mHWVirtExExclusive;
data.fNestedPaging = !!mHWData->mHWVirtExNestedPagingEnabled;
data.fLargePages = !!mHWData->mHWVirtExLargePagesEnabled;
data.fVPID = !!mHWData->mHWVirtExVPIDEnabled;
+ data.fUnrestrictedExecution = !!mHWData->mHWVirtExUXEnabled;
data.fHardwareVirtForce = !!mHWData->mHWVirtExForceEnabled;
data.fPAE = !!mHWData->mPAEEnabled;
+ data.enmLongMode = mHWData->mLongMode;
data.fSyntheticCpu = !!mHWData->mSyntheticCpu;
+ data.fTripleFaultReset = !!mHWData->mTripleFaultReset;
/* Standard and Extended CPUID leafs. */
data.llCpuIdLeafs.clear();
@@ -9728,14 +10629,25 @@ HRESULT Machine::saveHardware(settings::Hardware &data, settings::Debugging *pDb
data.mapBootOrder[i] = mHWData->mBootOrder[i];
// display
+ data.graphicsControllerType = mHWData->mGraphicsControllerType;
data.ulVRAMSizeMB = mHWData->mVRAMSize;
data.cMonitors = mHWData->mMonitorCount;
data.fAccelerate3D = !!mHWData->mAccelerate3DEnabled;
data.fAccelerate2DVideo = !!mHWData->mAccelerate2DVideoEnabled;
data.ulVideoCaptureHorzRes = mHWData->mVideoCaptureWidth;
data.ulVideoCaptureVertRes = mHWData->mVideoCaptureHeight;
- data.fVideoCaptureEnabled = !! mHWData->mVideoCaptureEnabled;
- data.strVideoCaptureFile = mHWData->mVideoCaptureFile;
+ data.ulVideoCaptureRate = mHWData->mVideoCaptureRate;
+ data.ulVideoCaptureFPS = mHWData->mVideoCaptureFPS;
+ data.fVideoCaptureEnabled = !!mHWData->mVideoCaptureEnabled;
+ for (unsigned i = 0; i < sizeof(data.u64VideoCaptureScreens) * 8; i++)
+ {
+ if (mHWData->maVideoCaptureScreens[i])
+ ASMBitSet(&data.u64VideoCaptureScreens, i);
+ else
+ ASMBitClear(&data.u64VideoCaptureScreens, i);
+ }
+ /* store relative video capture file if possible */
+ copyPathRelativeToMachine(mHWData->mVideoCaptureFile, data.strVideoCaptureFile);
/* VRDEServer settings (optional) */
rc = mVRDEServer->saveSettings(data.vrdeSettings);
@@ -9746,7 +10658,21 @@ HRESULT Machine::saveHardware(settings::Hardware &data, settings::Debugging *pDb
if (FAILED(rc)) throw rc;
/* USB Controller (required) */
- rc = mUSBController->saveSettings(data.usbController);
+ for (USBControllerList::const_iterator it = mUSBControllers->begin();
+ it != mUSBControllers->end();
+ ++it)
+ {
+ ComObjPtr<USBController> ctrl = *it;
+ settings::USBController settingsCtrl;
+
+ settingsCtrl.strName = ctrl->getName();
+ settingsCtrl.enmType = ctrl->getControllerType();
+
+ data.usbSettings.llUSBControllers.push_back(settingsCtrl);
+ }
+
+ /* USB device filters (required) */
+ rc = mUSBDeviceFilters->saveSettings(data.usbSettings);
if (FAILED(rc)) throw rc;
/* Network adapters (required) */
@@ -9854,11 +10780,11 @@ HRESULT Machine::saveHardware(settings::Hardware &data, settings::Debugging *pDb
// guest properties
data.llGuestProperties.clear();
#ifdef VBOX_WITH_GUEST_PROPS
- for (HWData::GuestPropertyList::const_iterator it = mHWData->mGuestProperties.begin();
+ for (HWData::GuestPropertyMap::const_iterator it = mHWData->mGuestProperties.begin();
it != mHWData->mGuestProperties.end();
++it)
{
- HWData::GuestProperty property = *it;
+ HWData::GuestProperty property = it->second;
/* Remove transient guest properties at shutdown unless we
* are saving state */
@@ -9869,7 +10795,7 @@ HRESULT Machine::saveHardware(settings::Hardware &data, settings::Debugging *pDb
|| property.mFlags & guestProp::TRANSRESET))
continue;
settings::GuestProperty prop;
- prop.strName = property.strName;
+ prop.strName = it->first;
prop.strValue = property.strValue;
prop.timestamp = property.mTimestamp;
char szFlags[guestProp::MAX_FLAGS_LEN + 1];
@@ -9886,6 +10812,8 @@ HRESULT Machine::saveHardware(settings::Hardware &data, settings::Debugging *pDb
*pDbg = mHWData->mDebugging;
*pAutostart = mHWData->mAutostart;
+
+ data.strDefaultFrontend = mHWData->mDefaultFrontend;
}
catch(std::bad_alloc &)
{
@@ -9976,14 +10904,17 @@ HRESULT Machine::saveStorageDevices(ComObjPtr<StorageController> aStorageControl
dev.deviceType = pAttach->getType();
dev.lPort = pAttach->getPort();
dev.lDevice = pAttach->getDevice();
+ dev.fPassThrough = pAttach->getPassthrough();
+ /// @todo save setting once the hot-pluggable flag works
+ dev.fHotPluggable = false /* pAttach->getHotPluggable()*/;
if (pMedium)
{
if (pMedium->isHostDrive())
dev.strHostDriveSrc = pMedium->getLocationFull();
else
dev.uuid = pMedium->getId();
- dev.fPassThrough = pAttach->getPassthrough();
dev.fTempEject = pAttach->getTempEject();
+ dev.fNonRotational = pAttach->getNonRotational();
dev.fDiscard = pAttach->getDiscard();
}
@@ -10128,7 +11059,7 @@ void Machine::addMediumToRegistry(ComObjPtr<Medium> &pMedium)
* @note The progress object is not marked as completed, neither on success nor
* on failure. This is a responsibility of the caller.
*
- * @note Locks this object for writing.
+ * @note Locks this object and the media tree for writing.
*/
HRESULT Machine::createImplicitDiffs(IProgress *aProgress,
ULONG aWeight,
@@ -10151,6 +11082,7 @@ HRESULT Machine::createImplicitDiffs(IProgress *aProgress,
HRESULT rc = S_OK;
+ // use appropriate locked media map (online or offline)
MediumLockListMap lockedMediaOffline;
MediumLockListMap *lockedMediaMap;
if (aOnline)
@@ -10282,6 +11214,8 @@ HRESULT Machine::createImplicitDiffs(IProgress *aProgress,
if (aOnline)
{
alock.release();
+ /* The currently attached medium will be read-only, change
+ * the lock type to read. */
rc = pMediumLockList->Update(pMedium, false);
alock.acquire();
AssertComRCThrowRC(rc);
@@ -10296,16 +11230,7 @@ HRESULT Machine::createImplicitDiffs(IProgress *aProgress,
alock.acquire();
if (FAILED(rc)) throw rc;
- rc = lockedMediaMap->Unlock();
- AssertComRCThrowRC(rc);
- alock.release();
- rc = pMediumLockList->Append(diff, true);
- alock.acquire();
- AssertComRCThrowRC(rc);
- alock.release();
- rc = lockedMediaMap->Lock();
- alock.acquire();
- AssertComRCThrowRC(rc);
+ /* actual lock list update is done in Medium::commitMedia */
rc = diff->addBackReference(mData->mUuid);
AssertComRCThrowRC(rc);
@@ -10324,6 +11249,7 @@ HRESULT Machine::createImplicitDiffs(IProgress *aProgress,
false /* aTempEject */,
pAtt->getNonRotational(),
pAtt->getDiscard(),
+ pAtt->getHotPluggable(),
pAtt->getBandwidthGroup());
if (FAILED(rc)) throw rc;
@@ -10334,7 +11260,7 @@ HRESULT Machine::createImplicitDiffs(IProgress *aProgress,
}
catch (HRESULT aRC) { rc = aRC; }
- /* unlock all hard disks we locked */
+ /* unlock all hard disks we locked when there is no VM */
if (!aOnline)
{
ErrorInfoKeeper eik;
@@ -10343,14 +11269,6 @@ HRESULT Machine::createImplicitDiffs(IProgress *aProgress,
AssertComRC(rc1);
}
- if (FAILED(rc))
- {
- MultiResult mrc = rc;
-
- alock.release();
- mrc = deleteImplicitDiffs();
- }
-
return rc;
}
@@ -10361,99 +11279,225 @@ HRESULT Machine::createImplicitDiffs(IProgress *aProgress,
* Note that to delete hard disks created by #AttachDevice() this method is
* called from #fixupMedia() when the changes are rolled back.
*
- * @note Locks this object for writing.
+ * @note Locks this object and the media tree for writing.
*/
-HRESULT Machine::deleteImplicitDiffs()
+HRESULT Machine::deleteImplicitDiffs(bool aOnline)
{
+ LogFlowThisFunc(("aOnline=%d\n", aOnline));
+
AutoCaller autoCaller(this);
AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
- AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
- LogFlowThisFuncEnter();
+ AutoMultiWriteLock2 alock(this->lockHandle(),
+ &mParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
+ /* We absolutely must have backed up state. */
AssertReturn(mMediaData.isBackedUp(), E_FAIL);
- HRESULT rc = S_OK;
-
- MediaData::AttachmentList implicitAtts;
-
- const MediaData::AttachmentList &oldAtts = mMediaData.backedUpData()->mAttachments;
-
- /* enumerate new attachments */
+ /* Check if there are any implicitly created diff images. */
+ bool fImplicitDiffs = false;
for (MediaData::AttachmentList::const_iterator it = mMediaData->mAttachments.begin();
it != mMediaData->mAttachments.end();
++it)
{
- ComObjPtr<Medium> hd = (*it)->getMedium();
- if (hd.isNull())
- continue;
-
- if ((*it)->isImplicit())
- {
- /* deassociate and mark for deletion */
- LogFlowThisFunc(("Detaching '%s', pending deletion\n", (*it)->getLogName()));
- rc = hd->removeBackReference(mData->mUuid);
- AssertComRC(rc);
- implicitAtts.push_back(*it);
- continue;
- }
-
- /* was this hard disk attached before? */
- if (!findAttachment(oldAtts, hd))
+ const ComObjPtr<MediumAttachment> &pAtt = *it;
+ if (pAtt->isImplicit())
{
- /* no: de-associate */
- LogFlowThisFunc(("Detaching '%s', no deletion\n", (*it)->getLogName()));
- rc = hd->removeBackReference(mData->mUuid);
- AssertComRC(rc);
- continue;
+ fImplicitDiffs = true;
+ break;
}
- LogFlowThisFunc(("Not detaching '%s'\n", (*it)->getLogName()));
}
+ /* If there is nothing to do, leave early. This saves lots of image locking
+ * effort. It also avoids a MachineStateChanged event without real reason.
+ * This is important e.g. when loading a VM config, because there should be
+ * no events. Otherwise API clients can become thoroughly confused for
+ * inaccessible VMs (the code for loading VM configs uses this method for
+ * cleanup if the config makes no sense), as they take such events as an
+ * indication that the VM is alive, and they would force the VM config to
+ * be reread, leading to an endless loop. */
+ if (!fImplicitDiffs)
+ return S_OK;
- /* rollback hard disk changes */
- mMediaData.rollback();
+ HRESULT rc = S_OK;
+ MachineState_T oldState = mData->mMachineState;
+
+ /* will release the lock before the potentially lengthy operation,
+ * so protect with the special state (unless already protected) */
+ if ( oldState != MachineState_Saving
+ && oldState != MachineState_LiveSnapshotting
+ && oldState != MachineState_RestoringSnapshot
+ && oldState != MachineState_DeletingSnapshot
+ && oldState != MachineState_DeletingSnapshotOnline
+ && oldState != MachineState_DeletingSnapshotPaused
+ )
+ setMachineState(MachineState_SettingUp);
- MultiResult mrc(S_OK);
+ // use appropriate locked media map (online or offline)
+ MediumLockListMap lockedMediaOffline;
+ MediumLockListMap *lockedMediaMap;
+ if (aOnline)
+ lockedMediaMap = &mData->mSession.mLockedMedia;
+ else
+ lockedMediaMap = &lockedMediaOffline;
- /* delete unused implicit diffs */
- if (implicitAtts.size() != 0)
+ try
{
- /* will release the lock before the potentially lengthy
- * operation, so protect with the special state (unless already
- * protected) */
- MachineState_T oldState = mData->mMachineState;
- if ( oldState != MachineState_Saving
- && oldState != MachineState_LiveSnapshotting
- && oldState != MachineState_RestoringSnapshot
- && oldState != MachineState_DeletingSnapshot
- && oldState != MachineState_DeletingSnapshotOnline
- && oldState != MachineState_DeletingSnapshotPaused
- )
- setMachineState(MachineState_SettingUp);
+ if (!aOnline)
+ {
+ /* lock all attached hard disks early to detect "in use"
+ * situations before deleting actual diffs */
+ for (MediaData::AttachmentList::const_iterator it = mMediaData->mAttachments.begin();
+ it != mMediaData->mAttachments.end();
+ ++it)
+ {
+ MediumAttachment* pAtt = *it;
+ if (pAtt->getType() == DeviceType_HardDisk)
+ {
+ Medium* pMedium = pAtt->getMedium();
+ Assert(pMedium);
- alock.release();
+ MediumLockList *pMediumLockList(new MediumLockList());
+ alock.release();
+ rc = pMedium->createMediumLockList(true /* fFailIfInaccessible */,
+ false /* fMediumLockWrite */,
+ NULL,
+ *pMediumLockList);
+ alock.acquire();
- for (MediaData::AttachmentList::const_iterator it = implicitAtts.begin();
- it != implicitAtts.end();
+ if (FAILED(rc))
+ {
+ delete pMediumLockList;
+ throw rc;
+ }
+
+ rc = lockedMediaMap->Insert(pAtt, pMediumLockList);
+ if (FAILED(rc))
+ throw rc;
+ }
+ }
+
+ if (FAILED(rc))
+ throw rc;
+ } // end of offline
+
+ /* Lock lists are now up to date and include implicitly created media */
+
+ /* Go through remembered attachments and delete all implicitly created
+ * diffs and fix up the attachment information */
+ const MediaData::AttachmentList &oldAtts = mMediaData.backedUpData()->mAttachments;
+ MediaData::AttachmentList implicitAtts;
+ for (MediaData::AttachmentList::const_iterator it = mMediaData->mAttachments.begin();
+ it != mMediaData->mAttachments.end();
++it)
{
- LogFlowThisFunc(("Deleting '%s'\n", (*it)->getLogName()));
- ComObjPtr<Medium> hd = (*it)->getMedium();
+ ComObjPtr<MediumAttachment> pAtt = *it;
+ ComObjPtr<Medium> pMedium = pAtt->getMedium();
+ if (pMedium.isNull())
+ continue;
- rc = hd->deleteStorage(NULL /*aProgress*/, true /*aWait*/);
- AssertMsg(SUCCEEDED(rc), ("rc=%Rhrc it=%s hd=%s\n", rc, (*it)->getLogName(), hd->getLocationFull().c_str() ));
- mrc = rc;
+ // Implicit attachments go on the list for deletion and back references are removed.
+ if (pAtt->isImplicit())
+ {
+ /* Deassociate and mark for deletion */
+ LogFlowThisFunc(("Detaching '%s', pending deletion\n", pAtt->getLogName()));
+ rc = pMedium->removeBackReference(mData->mUuid);
+ if (FAILED(rc))
+ throw rc;
+ implicitAtts.push_back(pAtt);
+ continue;
+ }
+
+ /* Was this medium attached before? */
+ if (!findAttachment(oldAtts, pMedium))
+ {
+ /* no: de-associate */
+ LogFlowThisFunc(("Detaching '%s', no deletion\n", pAtt->getLogName()));
+ rc = pMedium->removeBackReference(mData->mUuid);
+ if (FAILED(rc))
+ throw rc;
+ continue;
+ }
+ LogFlowThisFunc(("Not detaching '%s'\n", pAtt->getLogName()));
}
- alock.acquire();
+ /* If there are implicit attachments to delete, throw away the lock
+ * map contents (which will unlock all media) since the medium
+ * attachments will be rolled back. Below we need to completely
+ * recreate the lock map anyway since it is infinitely complex to
+ * do this incrementally (would need reconstructing each attachment
+ * change, which would be extremely hairy). */
+ if (implicitAtts.size() != 0)
+ {
+ ErrorInfoKeeper eik;
+
+ HRESULT rc1 = lockedMediaMap->Clear();
+ AssertComRC(rc1);
+ }
+
+ /* rollback hard disk changes */
+ mMediaData.rollback();
+
+ MultiResult mrc(S_OK);
+
+ // Delete unused implicit diffs.
+ if (implicitAtts.size() != 0)
+ {
+ alock.release();
+
+ for (MediaData::AttachmentList::const_iterator it = implicitAtts.begin();
+ it != implicitAtts.end();
+ ++it)
+ {
+ // Remove medium associated with this attachment.
+ ComObjPtr<MediumAttachment> pAtt = *it;
+ Assert(pAtt);
+ LogFlowThisFunc(("Deleting '%s'\n", pAtt->getLogName()));
+ ComObjPtr<Medium> pMedium = pAtt->getMedium();
+ Assert(pMedium);
+
+ rc = pMedium->deleteStorage(NULL /*aProgress*/, true /*aWait*/);
+ // continue on delete failure, just collect error messages
+ AssertMsg(SUCCEEDED(rc), ("rc=%Rhrc it=%s hd=%s\n", rc, pAtt->getLogName(), pMedium->getLocationFull().c_str() ));
+ mrc = rc;
+ }
+
+ alock.acquire();
+
+ /* if there is a VM recreate media lock map as mentioned above,
+ * otherwise it is a waste of time and we leave things unlocked */
+ if (aOnline)
+ {
+ const ComObjPtr<SessionMachine> pMachine = mData->mSession.mMachine;
+ /* must never be NULL, but better safe than sorry */
+ if (!pMachine.isNull())
+ {
+ alock.release();
+ rc = mData->mSession.mMachine->lockMedia();
+ alock.acquire();
+ if (FAILED(rc))
+ throw rc;
+ }
+ }
+ }
+ }
+ catch (HRESULT aRC) {rc = aRC;}
+
+ if (mData->mMachineState == MachineState_SettingUp)
+ setMachineState(oldState);
+
+ /* unlock all hard disks we locked when there is no VM */
+ if (!aOnline)
+ {
+ ErrorInfoKeeper eik;
- if (mData->mMachineState == MachineState_SettingUp)
- setMachineState(oldState);
+ HRESULT rc1 = lockedMediaMap->Clear();
+ AssertComRC(rc1);
}
- return mrc;
+ return rc;
}
+
/**
* Looks through the given list of media attachments for one with the given parameters
* and returns it, or NULL if not found. The list is a parameter so that backup lists
@@ -10822,11 +11866,21 @@ void Machine::commitMedia(bool aOnline /*= false*/)
/* unlock since medium is not used anymore */
MediumLockList *pMediumLockList;
rc = mData->mSession.mLockedMedia.Get(pAttach, pMediumLockList);
- AssertComRC(rc);
- if (pMediumLockList)
+ if (RT_UNLIKELY(rc == VBOX_E_INVALID_OBJECT_STATE))
+ {
+ /* this happens for online snapshots, there the attachment
+ * is changing, but only to a diff image created under
+ * the old one, so there is no separate lock list */
+ Assert(!pMediumLockList);
+ }
+ else
{
- rc = mData->mSession.mLockedMedia.Remove(pAttach);
AssertComRC(rc);
+ if (pMediumLockList)
+ {
+ rc = mData->mSession.mLockedMedia.Remove(pAttach);
+ AssertComRC(rc);
+ }
}
}
}
@@ -10881,11 +11935,10 @@ void Machine::commitMedia(bool aOnline /*= false*/)
void Machine::rollbackMedia()
{
AutoCaller autoCaller(this);
- AssertComRCReturnVoid (autoCaller.rc());
-
- AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+ AssertComRCReturnVoid(autoCaller.rc());
- LogFlowThisFunc(("Entering\n"));
+ // AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+ LogFlowThisFunc(("Entering rollbackMedia\n"));
HRESULT rc = S_OK;
@@ -10927,7 +11980,7 @@ void Machine::rollbackMedia()
/** @todo convert all this Machine-based voodoo to MediumAttachment
* based rollback logic. */
- deleteImplicitDiffs();
+ deleteImplicitDiffs(Global::IsOnline(mData->mMachineState));
return;
}
@@ -11011,6 +12064,40 @@ void Machine::rollback(bool aNotify)
}
}
+ if (!mUSBControllers.isNull())
+ {
+ if (mUSBControllers.isBackedUp())
+ {
+ /* unitialize all new devices (absent in the backed up list). */
+ USBControllerList::const_iterator it = mUSBControllers->begin();
+ USBControllerList *backedList = mUSBControllers.backedUpData();
+ while (it != mUSBControllers->end())
+ {
+ if ( std::find(backedList->begin(), backedList->end(), *it)
+ == backedList->end()
+ )
+ {
+ (*it)->uninit();
+ }
+ ++it;
+ }
+
+ /* restore the list */
+ mUSBControllers.rollback();
+ }
+
+ /* rollback any changes to devices after restoring the list */
+ if (mData->flModifications & IsModified_USB)
+ {
+ USBControllerList::const_iterator it = mUSBControllers->begin();
+ while (it != mUSBControllers->end())
+ {
+ (*it)->rollback();
+ ++it;
+ }
+ }
+ }
+
mUserData.rollback();
mHWData.rollback();
@@ -11027,8 +12114,8 @@ void Machine::rollback(bool aNotify)
if (mAudioAdapter)
mAudioAdapter->rollback();
- if (mUSBController && (mData->flModifications & IsModified_USB))
- mUSBController->rollback();
+ if (mUSBDeviceFilters && (mData->flModifications & IsModified_USB))
+ mUSBDeviceFilters->rollback();
if (mBandwidthControl && (mData->flModifications & IsModified_BandwidthControl))
mBandwidthControl->rollback();
@@ -11128,12 +12215,12 @@ void Machine::commit()
mHWData.commit();
if (mMediaData.isBackedUp())
- commitMedia();
+ commitMedia(Global::IsOnline(mData->mMachineState));
mBIOSSettings->commit();
mVRDEServer->commit();
mAudioAdapter->commit();
- mUSBController->commit();
+ mUSBDeviceFilters->commit();
mBandwidthControl->commit();
/* Since mNetworkAdapters is a list which might have been changed (resized)
@@ -11263,6 +12350,77 @@ void Machine::commit()
}
}
+ bool commitUSBControllers = false;
+
+ if (mUSBControllers.isBackedUp())
+ {
+ mUSBControllers.commit();
+
+ if (mPeer)
+ {
+ /* Commit all changes to new controllers (this will reshare data with
+ * peers for those who have peers) */
+ USBControllerList *newList = new USBControllerList();
+ USBControllerList::const_iterator it = mUSBControllers->begin();
+ while (it != mUSBControllers->end())
+ {
+ (*it)->commit();
+
+ /* look if this controller has a peer device */
+ ComObjPtr<USBController> peer = (*it)->getPeer();
+ if (!peer)
+ {
+ /* no peer means the device is a newly created one;
+ * create a peer owning data this device share it with */
+ peer.createObject();
+ peer->init(mPeer, *it, true /* aReshare */);
+ }
+ else
+ {
+ /* remove peer from the old list */
+ mPeer->mUSBControllers->remove(peer);
+ }
+ /* and add it to the new list */
+ newList->push_back(peer);
+
+ ++it;
+ }
+
+ /* uninit old peer's controllers that are left */
+ it = mPeer->mUSBControllers->begin();
+ while (it != mPeer->mUSBControllers->end())
+ {
+ (*it)->uninit();
+ ++it;
+ }
+
+ /* attach new list of controllers to our peer */
+ mPeer->mUSBControllers.attach(newList);
+ }
+ else
+ {
+ /* we have no peer (our parent is the newly created machine);
+ * just commit changes to devices */
+ commitUSBControllers = true;
+ }
+ }
+ else
+ {
+ /* the list of controllers itself is not changed,
+ * just commit changes to controllers themselves */
+ commitUSBControllers = true;
+ }
+
+ if (commitUSBControllers)
+ {
+ USBControllerList::const_iterator it = mUSBControllers->begin();
+ while (it != mUSBControllers->end())
+ {
+ (*it)->commit();
+ ++it;
+ }
+ }
+
if (isSessionMachine())
{
/* attach new data to the primary machine and reshare it */
@@ -11311,7 +12469,7 @@ void Machine::copyFrom(Machine *aThat)
mBIOSSettings->copyFrom(aThat->mBIOSSettings);
mVRDEServer->copyFrom(aThat->mVRDEServer);
mAudioAdapter->copyFrom(aThat->mAudioAdapter);
- mUSBController->copyFrom(aThat->mUSBController);
+ mUSBDeviceFilters->copyFrom(aThat->mUSBDeviceFilters);
mBandwidthControl->copyFrom(aThat->mBandwidthControl);
/* create private copies of all controllers */
@@ -11327,6 +12485,19 @@ void Machine::copyFrom(Machine *aThat)
mStorageControllers->push_back(ctrl);
}
+ /* create private copies of all USB controllers */
+ mUSBControllers.backup();
+ mUSBControllers->clear();
+ for (USBControllerList::iterator it = aThat->mUSBControllers->begin();
+ it != aThat->mUSBControllers->end();
+ ++it)
+ {
+ ComObjPtr<USBController> ctrl;
+ ctrl.createObject();
+ ctrl->initCopy(this, *it);
+ mUSBControllers->push_back(ctrl);
+ }
+
mNetworkAdapters.resize(aThat->mNetworkAdapters.size());
for (ULONG slot = 0; slot < mNetworkAdapters.size(); slot++)
mNetworkAdapters[slot]->copyFrom(aThat->mNetworkAdapters[slot]);
@@ -11363,6 +12534,26 @@ bool Machine::isControllerHotplugCapable(StorageControllerType_T enmCtrlType)
#ifdef VBOX_WITH_RESOURCE_USAGE_API
+void Machine::getDiskList(MediaList &list)
+{
+ for (MediaData::AttachmentList::const_iterator it = mMediaData->mAttachments.begin();
+ it != mMediaData->mAttachments.end();
+ ++it)
+ {
+ MediumAttachment* pAttach = *it;
+ /* just in case */
+ AssertStmt(pAttach, continue);
+
+ AutoCaller localAutoCallerA(pAttach);
+ if (FAILED(localAutoCallerA.rc())) continue;
+
+ AutoReadLock local_alockA(pAttach COMMA_LOCKVAL_SRC_POS);
+
+ if (pAttach->getType() == DeviceType_HardDisk)
+ list.push_back(pAttach->getMedium());
+ }
+}
+
void Machine::registerMetrics(PerformanceCollector *aCollector, Machine *aMachine, RTPROCESS pid)
{
AssertReturnVoid(isWriteLockOnCurrentThread());
@@ -11376,6 +12567,12 @@ void Machine::registerMetrics(PerformanceCollector *aCollector, Machine *aMachin
"Percentage of processor time spent in kernel mode by the VM process.");
pm::SubMetric *ramUsageUsed = new pm::SubMetric("RAM/Usage/Used",
"Size of resident portion of VM process in memory.");
+ pm::SubMetric *diskUsageUsed = new pm::SubMetric("Disk/Usage/Used",
+ "Actual size of all VM disks combined.");
+ pm::SubMetric *machineNetRx = new pm::SubMetric("Net/Rate/Rx",
+ "Network receive rate.");
+ pm::SubMetric *machineNetTx = new pm::SubMetric("Net/Rate/Tx",
+ "Network transmit rate.");
/* Create and register base metrics */
pm::BaseMetric *cpuLoad = new pm::MachineCpuLoadRaw(hal, aMachine, pid,
cpuLoadUser, cpuLoadKernel);
@@ -11383,6 +12580,11 @@ void Machine::registerMetrics(PerformanceCollector *aCollector, Machine *aMachin
pm::BaseMetric *ramUsage = new pm::MachineRamUsage(hal, aMachine, pid,
ramUsageUsed);
aCollector->registerBaseMetric(ramUsage);
+ MediaList disks;
+ getDiskList(disks);
+ pm::BaseMetric *diskUsage = new pm::MachineDiskUsage(hal, aMachine, disks,
+ diskUsageUsed);
+ aCollector->registerBaseMetric(diskUsage);
aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser, 0));
aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
@@ -11407,6 +12609,14 @@ void Machine::registerMetrics(PerformanceCollector *aCollector, Machine *aMachin
aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
new pm::AggregateMax()));
+ aCollector->registerMetric(new pm::Metric(diskUsage, diskUsageUsed, 0));
+ aCollector->registerMetric(new pm::Metric(diskUsage, diskUsageUsed,
+ new pm::AggregateAvg()));
+ aCollector->registerMetric(new pm::Metric(diskUsage, diskUsageUsed,
+ new pm::AggregateMin()));
+ aCollector->registerMetric(new pm::Metric(diskUsage, diskUsageUsed,
+ new pm::AggregateMax()));
+
/* Guest metrics collector */
mCollectorGuest = new pm::CollectorGuest(aMachine, pid);
@@ -11432,6 +12642,10 @@ void Machine::registerMetrics(PerformanceCollector *aCollector, Machine *aMachin
pm::SubMetric *guestPagedTotal = new pm::SubMetric("Guest/Pagefile/Usage/Total", "Total amount of space in the page file.");
/* Create and register base metrics */
+ pm::BaseMetric *machineNetRate = new pm::MachineNetRate(mCollectorGuest, aMachine,
+ machineNetRx, machineNetTx);
+ aCollector->registerBaseMetric(machineNetRate);
+
pm::BaseMetric *guestCpuLoad = new pm::GuestCpuLoad(mCollectorGuest, aMachine,
guestLoadUser, guestLoadKernel, guestLoadIdle);
aCollector->registerBaseMetric(guestCpuLoad);
@@ -11442,6 +12656,16 @@ void Machine::registerMetrics(PerformanceCollector *aCollector, Machine *aMachin
guestMemCache, guestPagedTotal);
aCollector->registerBaseMetric(guestCpuMem);
+ aCollector->registerMetric(new pm::Metric(machineNetRate, machineNetRx, 0));
+ aCollector->registerMetric(new pm::Metric(machineNetRate, machineNetRx, new pm::AggregateAvg()));
+ aCollector->registerMetric(new pm::Metric(machineNetRate, machineNetRx, new pm::AggregateMin()));
+ aCollector->registerMetric(new pm::Metric(machineNetRate, machineNetRx, new pm::AggregateMax()));
+
+ aCollector->registerMetric(new pm::Metric(machineNetRate, machineNetTx, 0));
+ aCollector->registerMetric(new pm::Metric(machineNetRate, machineNetTx, new pm::AggregateAvg()));
+ aCollector->registerMetric(new pm::Metric(machineNetRate, machineNetTx, new pm::AggregateMin()));
+ aCollector->registerMetric(new pm::Metric(machineNetRate, machineNetTx, new pm::AggregateMax()));
+
aCollector->registerMetric(new pm::Metric(guestCpuLoad, guestLoadUser, 0));
aCollector->registerMetric(new pm::Metric(guestCpuLoad, guestLoadUser, new pm::AggregateAvg()));
aCollector->registerMetric(new pm::Metric(guestCpuLoad, guestLoadUser, new pm::AggregateMin()));
@@ -11510,15 +12734,7 @@ HRESULT SessionMachine::FinalConstruct()
{
LogFlowThisFunc(("\n"));
-#if defined(RT_OS_WINDOWS)
- mIPCSem = NULL;
-#elif defined(RT_OS_OS2)
- mIPCSem = NULLHANDLE;
-#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
- mIPCSem = -1;
-#else
-# error "Port me!"
-#endif
+ mClientToken = NULL;
return BaseFinalConstruct();
}
@@ -11527,13 +12743,21 @@ void SessionMachine::FinalRelease()
{
LogFlowThisFunc(("\n"));
+ Assert(!mClientToken);
+ /* paranoia, should not hang around any more */
+ if (mClientToken)
+ {
+ delete mClientToken;
+ mClientToken = NULL;
+ }
+
uninit(Uninit::Unexpected);
BaseFinalRelease();
}
/**
- * @note Must be called only by Machine::openSession() from its own write lock.
+ * @note Must be called only by Machine::LockMachine() from its own write lock.
*/
HRESULT SessionMachine::init(Machine *aMachine)
{
@@ -11548,96 +12772,25 @@ HRESULT SessionMachine::init(Machine *aMachine)
AutoInitSpan autoInitSpan(this);
AssertReturn(autoInitSpan.isOk(), E_FAIL);
- /* create the interprocess semaphore */
-#if defined(RT_OS_WINDOWS)
- mIPCSemName = aMachine->mData->m_strConfigFileFull;
- for (size_t i = 0; i < mIPCSemName.length(); i++)
- if (mIPCSemName.raw()[i] == '\\')
- mIPCSemName.raw()[i] = '/';
- mIPCSem = ::CreateMutex(NULL, FALSE, mIPCSemName.raw());
- ComAssertMsgRet(mIPCSem,
- ("Cannot create IPC mutex '%ls', err=%d",
- mIPCSemName.raw(), ::GetLastError()),
- E_FAIL);
-#elif defined(RT_OS_OS2)
- Utf8Str ipcSem = Utf8StrFmt("\\SEM32\\VBOX\\VM\\{%RTuuid}",
- aMachine->mData->mUuid.raw());
- mIPCSemName = ipcSem;
- APIRET arc = ::DosCreateMutexSem((PSZ)ipcSem.c_str(), &mIPCSem, 0, FALSE);
- ComAssertMsgRet(arc == NO_ERROR,
- ("Cannot create IPC mutex '%s', arc=%ld",
- ipcSem.c_str(), arc),
- E_FAIL);
-#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
-# ifdef VBOX_WITH_NEW_SYS_V_KEYGEN
-# if defined(RT_OS_FREEBSD) && (HC_ARCH_BITS == 64)
- /** @todo Check that this still works correctly. */
- AssertCompileSize(key_t, 8);
-# else
- AssertCompileSize(key_t, 4);
-# endif
- key_t key;
- mIPCSem = -1;
- mIPCKey = "0";
- for (uint32_t i = 0; i < 1 << 24; i++)
- {
- key = ((uint32_t)'V' << 24) | i;
- int sem = ::semget(key, 1, S_IRUSR | S_IWUSR | IPC_CREAT | IPC_EXCL);
- if (sem >= 0 || (errno != EEXIST && errno != EACCES))
- {
- mIPCSem = sem;
- if (sem >= 0)
- mIPCKey = BstrFmt("%u", key);
- break;
- }
- }
-# else /* !VBOX_WITH_NEW_SYS_V_KEYGEN */
- Utf8Str semName = aMachine->mData->m_strConfigFileFull;
- char *pszSemName = NULL;
- RTStrUtf8ToCurrentCP(&pszSemName, semName);
- key_t key = ::ftok(pszSemName, 'V');
- RTStrFree(pszSemName);
-
- mIPCSem = ::semget(key, 1, S_IRWXU | S_IRWXG | S_IRWXO | IPC_CREAT);
-# endif /* !VBOX_WITH_NEW_SYS_V_KEYGEN */
+ HRESULT rc = S_OK;
- int errnoSave = errno;
- if (mIPCSem < 0 && errnoSave == ENOSYS)
+ /* create the machine client token */
+ try
{
- setError(E_FAIL,
- tr("Cannot create IPC semaphore. Most likely your host kernel lacks "
- "support for SysV IPC. Check the host kernel configuration for "
- "CONFIG_SYSVIPC=y"));
- return E_FAIL;
+ mClientToken = new ClientToken(aMachine, this);
+ if (!mClientToken->isReady())
+ {
+ delete mClientToken;
+ mClientToken = NULL;
+ rc = E_FAIL;
+ }
}
- /* ENOSPC can also be the result of VBoxSVC crashes without properly freeing
- * the IPC semaphores */
- if (mIPCSem < 0 && errnoSave == ENOSPC)
- {
-#ifdef RT_OS_LINUX
- setError(E_FAIL,
- tr("Cannot create IPC semaphore because the system limit for the "
- "maximum number of semaphore sets (SEMMNI), or the system wide "
- "maximum number of semaphores (SEMMNS) would be exceeded. The "
- "current set of SysV IPC semaphores can be determined from "
- "the file /proc/sysvipc/sem"));
-#else
- setError(E_FAIL,
- tr("Cannot create IPC semaphore because the system-imposed limit "
- "on the maximum number of allowed semaphores or semaphore "
- "identifiers system-wide would be exceeded"));
-#endif
- return E_FAIL;
+ catch (std::bad_alloc &)
+ {
+ rc = E_OUTOFMEMORY;
}
- ComAssertMsgRet(mIPCSem >= 0, ("Cannot create IPC semaphore, errno=%d", errnoSave),
- E_FAIL);
- /* set the initial value to 1 */
- int rv = ::semctl(mIPCSem, 0, SETVAL, 1);
- ComAssertMsgRet(rv == 0, ("Cannot init IPC semaphore, errno=%d", errno),
- E_FAIL);
-#else
-# error "Port me!"
-#endif
+ if (FAILED(rc))
+ return rc;
/* memorize the peer Machine */
unconst(mPeer) = aMachine;
@@ -11663,6 +12816,17 @@ HRESULT SessionMachine::init(Machine *aMachine)
mStorageControllers->push_back(ctl);
}
+ mUSBControllers.allocate();
+ for (USBControllerList::const_iterator it = aMachine->mUSBControllers->begin();
+ it != aMachine->mUSBControllers->end();
+ ++it)
+ {
+ ComObjPtr<USBController> ctl;
+ ctl.createObject();
+ ctl->init(this, *it);
+ mUSBControllers->push_back(ctl);
+ }
+
unconst(mBIOSSettings).createObject();
mBIOSSettings->init(this, aMachine->mBIOSSettings);
/* create another VRDEServer object that will be mutable */
@@ -11683,9 +12847,10 @@ HRESULT SessionMachine::init(Machine *aMachine)
unconst(mParallelPorts[slot]).createObject();
mParallelPorts[slot]->init(this, aMachine->mParallelPorts[slot]);
}
- /* create another USB controller object that will be mutable */
- unconst(mUSBController).createObject();
- mUSBController->init(this, aMachine->mUSBController);
+
+ /* create another USB device filters object that will be mutable */
+ unconst(mUSBDeviceFilters).createObject();
+ mUSBDeviceFilters->init(this, aMachine->mUSBDeviceFilters);
/* create a list of network adapters that will be mutable */
mNetworkAdapters.resize(aMachine->mNetworkAdapters.size());
@@ -11705,13 +12870,16 @@ HRESULT SessionMachine::init(Machine *aMachine)
/* Confirm a successful initialization when it's the case */
autoInitSpan.setSucceeded();
+ miNATNetworksStarted = 0;
+
LogFlowThisFuncLeave();
- return S_OK;
+ return rc;
}
/**
* Uninitializes this session object. If the reason is other than
- * Uninit::Unexpected, then this method MUST be called from #checkForDeath().
+ * Uninit::Unexpected, then this method MUST be called from #checkForDeath()
+ * or the client watcher code.
*
* @param aReason uninitialization reason
*
@@ -11747,24 +12915,12 @@ void SessionMachine::uninit(Uninit::Reason aReason)
* below, the following is enough.
*/
LogFlowThisFunc(("Initialization failed.\n"));
-#if defined(RT_OS_WINDOWS)
- if (mIPCSem)
- ::CloseHandle(mIPCSem);
- mIPCSem = NULL;
-#elif defined(RT_OS_OS2)
- if (mIPCSem != NULLHANDLE)
- ::DosCloseMutexSem(mIPCSem);
- mIPCSem = NULLHANDLE;
-#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
- if (mIPCSem >= 0)
- ::semctl(mIPCSem, 0, IPC_RMID);
- mIPCSem = -1;
-# ifdef VBOX_WITH_NEW_SYS_V_KEYGEN
- mIPCKey = "0";
-# endif /* VBOX_WITH_NEW_SYS_V_KEYGEN */
-#else
-# error "Port me!"
-#endif
+ /* destroy the machine client token */
+ if (mClientToken)
+ {
+ delete mClientToken;
+ mClientToken = NULL;
+ }
uninitDataAndChildObjects();
mData.free();
unconst(mParent) = NULL;
@@ -11792,7 +12948,7 @@ void SessionMachine::uninit(Uninit::Reason aReason)
*
* This is identical to SessionMachine::DetachAllUSBDevices except
* for the aAbnormal argument. */
- HRESULT rc = mUSBController->notifyProxy(false /* aInsertFilters */);
+ HRESULT rc = mUSBDeviceFilters->notifyProxy(false /* aInsertFilters */);
AssertComRC(rc);
NOREF(rc);
@@ -11803,23 +12959,17 @@ void SessionMachine::uninit(Uninit::Reason aReason)
#endif /* VBOX_WITH_USB */
// we need to lock this object in uninit() because the lock is shared
- // with mPeer (as well as data we modify below). mParent->addProcessToReap()
- // and others need mParent lock, and USB needs host lock.
+ // with mPeer (as well as data we modify below). mParent lock is needed
+ // by several calls to it, and USB needs host lock.
AutoMultiWriteLock3 multilock(mParent, mParent->host(), this COMMA_LOCKVAL_SRC_POS);
-#if 0
- // Trigger async cleanup tasks, avoid doing things here which are not
- // vital to be done immediately and maybe need more locks. This calls
- // Machine::unregisterMetrics().
- mParent->onMachineUninit(mPeer);
-#else
+#ifdef VBOX_WITH_RESOURCE_USAGE_API
/*
* It is safe to call Machine::unregisterMetrics() here because
* PerformanceCollector::samplerCallback no longer accesses guest methods
* holding the lock.
*/
unregisterMetrics(mParent->performanceCollector(), mPeer);
-#endif
/* The guest must be unregistered after its metrics (@bugref{5949}). */
LogAleksey(("{%p} " LOG_FN_FMT ": mCollectorGuest=%p\n",
this, __PRETTY_FUNCTION__, mCollectorGuest));
@@ -11829,6 +12979,7 @@ void SessionMachine::uninit(Uninit::Reason aReason)
// delete mCollectorGuest; => CollectorGuestManager::destroyUnregistered()
mCollectorGuest = NULL;
}
+#endif
if (aReason == Uninit::Abnormal)
{
@@ -11870,16 +13021,6 @@ void SessionMachine::uninit(Uninit::Reason aReason)
releaseSavedStateFile(strStateFile, NULL /* pSnapshotToIgnore */ );
}
- if (!mData->mSession.mType.isEmpty())
- {
- /* mType is not null when this machine's process has been started by
- * Machine::LaunchVMProcess(), therefore it is our child. We
- * need to queue the PID to reap the process (and avoid zombies on
- * Linux). */
- Assert(mData->mSession.mPID != NIL_RTPROCESS);
- mParent->addProcessToReap(mData->mSession.mPID);
- }
-
mData->mSession.mPID = NIL_RTPROCESS;
if (aReason == Uninit::Unexpected)
@@ -11910,6 +13051,33 @@ void SessionMachine::uninit(Uninit::Reason aReason)
mData->mSession.mRemoteControls.clear();
}
+ /* Remove all references to the NAT network service. The service will stop
+ * if all references (also from other VMs) are removed. */
+ for (; miNATNetworksStarted > 0; miNATNetworksStarted--)
+ {
+ for (ULONG slot = 0; slot < mNetworkAdapters.size(); slot++)
+ {
+ NetworkAttachmentType_T type;
+ HRESULT hrc;
+
+ hrc = mNetworkAdapters[slot]->COMGETTER(AttachmentType)(&type);
+ if ( SUCCEEDED(hrc)
+ && type == NetworkAttachmentType_NATNetwork)
+ {
+ Bstr name;
+ hrc = mNetworkAdapters[slot]->COMGETTER(NATNetwork)(name.asOutParam());
+ if (SUCCEEDED(hrc))
+ {
+ multilock.release();
+ LogRel(("VM '%s' stops using NAT network '%ls'\n",
+ mUserData->s.strName.c_str(), name.raw()));
+ mParent->natNetworkRefDec(name.raw());
+ multilock.acquire();
+ }
+ }
+ }
+ }
+
/*
* An expected uninitialization can come only from #checkForDeath().
* Otherwise it means that something's gone really wrong (for example,
@@ -11957,25 +13125,12 @@ void SessionMachine::uninit(Uninit::Reason aReason)
mData->mSession.mState = SessionState_Unlocked;
mData->mSession.mType.setNull();
- /* close the interprocess semaphore before leaving the exclusive lock */
-#if defined(RT_OS_WINDOWS)
- if (mIPCSem)
- ::CloseHandle(mIPCSem);
- mIPCSem = NULL;
-#elif defined(RT_OS_OS2)
- if (mIPCSem != NULLHANDLE)
- ::DosCloseMutexSem(mIPCSem);
- mIPCSem = NULLHANDLE;
-#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
- if (mIPCSem >= 0)
- ::semctl(mIPCSem, 0, IPC_RMID);
- mIPCSem = -1;
-# ifdef VBOX_WITH_NEW_SYS_V_KEYGEN
- mIPCKey = "0";
-# endif /* VBOX_WITH_NEW_SYS_V_KEYGEN */
-#else
-# error "Port me!"
-#endif
+ /* destroy the machine client token before leaving the exclusive lock */
+ if (mClientToken)
+ {
+ delete mClientToken;
+ mClientToken = NULL;
+ }
/* fire an event */
mParent->onSessionStateChange(mData->mUuid, SessionState_Unlocked);
@@ -12013,21 +13168,42 @@ RWLockHandle *SessionMachine::lockHandle() const
/**
* Passes collected guest statistics to performance collector object
*/
-STDMETHODIMP SessionMachine::ReportGuestStatistics(ULONG aValidStats, ULONG aCpuUser,
- ULONG aCpuKernel, ULONG aCpuIdle,
- ULONG aMemTotal, ULONG aMemFree,
- ULONG aMemBalloon, ULONG aMemShared,
- ULONG aMemCache, ULONG aPageTotal,
- ULONG aAllocVMM, ULONG aFreeVMM,
- ULONG aBalloonedVMM, ULONG aSharedVMM)
+STDMETHODIMP SessionMachine::ReportVmStatistics(ULONG aValidStats, ULONG aCpuUser,
+ ULONG aCpuKernel, ULONG aCpuIdle,
+ ULONG aMemTotal, ULONG aMemFree,
+ ULONG aMemBalloon, ULONG aMemShared,
+ ULONG aMemCache, ULONG aPageTotal,
+ ULONG aAllocVMM, ULONG aFreeVMM,
+ ULONG aBalloonedVMM, ULONG aSharedVMM,
+ ULONG aVmNetRx, ULONG aVmNetTx)
{
+#ifdef VBOX_WITH_RESOURCE_USAGE_API
if (mCollectorGuest)
mCollectorGuest->updateStats(aValidStats, aCpuUser, aCpuKernel, aCpuIdle,
aMemTotal, aMemFree, aMemBalloon, aMemShared,
aMemCache, aPageTotal, aAllocVMM, aFreeVMM,
- aBalloonedVMM, aSharedVMM);
+ aBalloonedVMM, aSharedVMM, aVmNetRx, aVmNetTx);
return S_OK;
+#else
+ NOREF(aValidStats);
+ NOREF(aCpuUser);
+ NOREF(aCpuKernel);
+ NOREF(aCpuIdle);
+ NOREF(aMemTotal);
+ NOREF(aMemFree);
+ NOREF(aMemBalloon);
+ NOREF(aMemShared);
+ NOREF(aMemCache);
+ NOREF(aPageTotal);
+ NOREF(aAllocVMM);
+ NOREF(aFreeVMM);
+ NOREF(aBalloonedVMM);
+ NOREF(aSharedVMM);
+ NOREF(aVmNetRx);
+ NOREF(aVmNetTx);
+ return E_NOTIMPL;
+#endif
}
/**
@@ -12054,31 +13230,6 @@ STDMETHODIMP SessionMachine::UpdateState(MachineState_T aMachineState)
}
/**
- * @note Locks this object for reading.
- */
-STDMETHODIMP SessionMachine::GetIPCId(BSTR *aId)
-{
- AutoCaller autoCaller(this);
- AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
-
- AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
- mIPCSemName.cloneTo(aId);
- return S_OK;
-#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
-# ifdef VBOX_WITH_NEW_SYS_V_KEYGEN
- mIPCKey.cloneTo(aId);
-# else /* !VBOX_WITH_NEW_SYS_V_KEYGEN */
- mData->m_strConfigFileFull.cloneTo(aId);
-# endif /* !VBOX_WITH_NEW_SYS_V_KEYGEN */
- return S_OK;
-#else
-# error "Port me!"
-#endif
-}
-
-/**
* @note Locks this object for writing.
*/
STDMETHODIMP SessionMachine::BeginPowerUp(IProgress *aProgress)
@@ -12095,6 +13246,37 @@ STDMETHODIMP SessionMachine::BeginPowerUp(IProgress *aProgress)
if (!mData->mSession.mProgress.isNull())
mData->mSession.mProgress->setOtherProgressObject(aProgress);
+ /* If we didn't reference the NAT network service yet, add a reference to
+ * force a start */
+ if (miNATNetworksStarted < 1)
+ {
+ for (ULONG slot = 0; slot < mNetworkAdapters.size(); slot++)
+ {
+ NetworkAttachmentType_T type;
+ HRESULT hrc;
+ hrc = mNetworkAdapters[slot]->COMGETTER(AttachmentType)(&type);
+ if ( SUCCEEDED(hrc)
+ && type == NetworkAttachmentType_NATNetwork)
+ {
+ Bstr name;
+ hrc = mNetworkAdapters[slot]->COMGETTER(NATNetwork)(name.asOutParam());
+ if (SUCCEEDED(hrc))
+ {
+ LogRel(("VM '%s' starts using NAT network '%ls'\n",
+ mUserData->s.strName.c_str(), name.raw()));
+ mPeer->lockHandle()->unlockWrite();
+ mParent->natNetworkRefInc(name.raw());
+#ifdef RT_LOCK_STRICT
+ mPeer->lockHandle()->lockWrite(RT_SRC_POS);
+#else
+ mPeer->lockHandle()->lockWrite();
+#endif
+ }
+ }
+ }
+ miNATNetworksStarted++;
+ }
+
LogFlowThisFunc(("returns S_OK.\n"));
return S_OK;
}
@@ -12240,7 +13422,7 @@ STDMETHODIMP SessionMachine::RunUSBDeviceFilters(IUSBDevice *aUSBDevice,
AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
#ifdef VBOX_WITH_USB
- *aMatched = mUSBController->hasMatchingFilter(aUSBDevice, aMaskedIfs);
+ *aMatched = mUSBDeviceFilters->hasMatchingFilter(aUSBDevice, aMaskedIfs);
#else
NOREF(aUSBDevice);
NOREF(aMaskedIfs);
@@ -12312,7 +13494,7 @@ STDMETHODIMP SessionMachine::AutoCaptureUSBDevices()
AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
#ifdef VBOX_WITH_USB
- HRESULT rc = mUSBController->notifyProxy(true /* aInsertFilters */);
+ HRESULT rc = mUSBDeviceFilters->notifyProxy(true /* aInsertFilters */);
AssertComRC(rc);
NOREF(rc);
@@ -12342,7 +13524,7 @@ STDMETHODIMP SessionMachine::DetachAllUSBDevices(BOOL aDone)
AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
#ifdef VBOX_WITH_USB
- HRESULT rc = mUSBController->notifyProxy(false /* aInsertFilters */);
+ HRESULT rc = mUSBDeviceFilters->notifyProxy(false /* aInsertFilters */);
AssertComRC(rc);
NOREF(rc);
@@ -12591,18 +13773,18 @@ STDMETHODIMP SessionMachine::PullGuestProperties(ComSafeArrayOut(BSTR, aNames),
com::SafeArray<LONG64> timestamps(cEntries);
com::SafeArray<BSTR> flags(cEntries);
unsigned i = 0;
- for (HWData::GuestPropertyList::iterator it = mHWData->mGuestProperties.begin();
+ for (HWData::GuestPropertyMap::iterator it = mHWData->mGuestProperties.begin();
it != mHWData->mGuestProperties.end();
++it)
{
char szFlags[MAX_FLAGS_LEN + 1];
- it->strName.cloneTo(&names[i]);
- it->strValue.cloneTo(&values[i]);
- timestamps[i] = it->mTimestamp;
+ it->first.cloneTo(&names[i]);
+ it->second.strValue.cloneTo(&values[i]);
+ timestamps[i] = it->second.mTimestamp;
/* If it is NULL, keep it NULL. */
- if (it->mFlags)
+ if (it->second.mFlags)
{
- writeFlags(it->mFlags, szFlags);
+ writeFlags(it->second.mFlags, szFlags);
Bstr(szFlags).cloneTo(&flags[i]);
}
else
@@ -12638,8 +13820,8 @@ STDMETHODIMP SessionMachine::PushGuestProperty(IN_BSTR aName,
/*
* Convert input up front.
*/
- Utf8Str utf8Name(aName);
- uint32_t fFlags = NILFLAG;
+ Utf8Str utf8Name(aName);
+ uint32_t fFlags = NILFLAG;
if (aFlags)
{
Utf8Str utf8Flags(aFlags);
@@ -12665,43 +13847,40 @@ STDMETHODIMP SessionMachine::PushGuestProperty(IN_BSTR aName,
case MachineState_DeletingSnapshotOnline:
case MachineState_DeletingSnapshotPaused:
case MachineState_Saving:
+ case MachineState_Stopping:
break;
default:
-#ifndef DEBUG_sunlover
AssertMsgFailedReturn(("%s\n", Global::stringifyMachineState(mData->mMachineState)),
VBOX_E_INVALID_VM_STATE);
-#else
- return VBOX_E_INVALID_VM_STATE;
-#endif
}
setModified(IsModified_MachineData);
mHWData.backup();
- /** @todo r=bird: The careful memory handling doesn't work out here because
- * the catch block won't undo any damage we've done. So, if push_back throws
- * bad_alloc then you've lost the value.
- *
- * Another thing. Doing a linear search here isn't extremely efficient, esp.
- * since values that changes actually bubbles to the end of the list. Using
- * something that has an efficient lookup and can tolerate a bit of updates
- * would be nice. RTStrSpace is one suggestion (it's not perfect). Some
- * combination of RTStrCache (for sharing names and getting uniqueness into
- * the bargain) and hash/tree is another. */
- for (HWData::GuestPropertyList::iterator iter = mHWData->mGuestProperties.begin();
- iter != mHWData->mGuestProperties.end();
- ++iter)
- if (utf8Name == iter->strName)
+ bool fDelete = !RT_VALID_PTR(aValue) || *(aValue) == '\0';
+ HWData::GuestPropertyMap::iterator it = mHWData->mGuestProperties.find(utf8Name);
+ if (it != mHWData->mGuestProperties.end())
+ {
+ if (!fDelete)
{
- mHWData->mGuestProperties.erase(iter);
- mData->mGuestPropertiesModified = TRUE;
- break;
+ it->second.strValue = aValue;
+ it->second.mTimestamp = aTimestamp;
+ it->second.mFlags = fFlags;
}
- if (aValue != NULL)
+ else
+ mHWData->mGuestProperties.erase(it);
+
+ mData->mGuestPropertiesModified = TRUE;
+ }
+ else if (!fDelete)
{
- HWData::GuestProperty property = { aName, aValue, aTimestamp, fFlags };
- mHWData->mGuestProperties.push_back(property);
+ HWData::GuestProperty prop;
+ prop.strValue = aValue;
+ prop.mTimestamp = aTimestamp;
+ prop.mFlags = fFlags;
+
+ mHWData->mGuestProperties[utf8Name] = prop;
mData->mGuestPropertiesModified = TRUE;
}
@@ -12733,6 +13912,29 @@ STDMETHODIMP SessionMachine::PushGuestProperty(IN_BSTR aName,
#endif
}
+STDMETHODIMP SessionMachine::LockMedia()
+{
+ AutoCaller autoCaller(this);
+ AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
+
+ AutoMultiWriteLock2 alock(this->lockHandle(),
+ &mParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
+
+ AssertReturn( mData->mMachineState == MachineState_Starting
+ || mData->mMachineState == MachineState_Restoring
+ || mData->mMachineState == MachineState_TeleportingIn, E_FAIL);
+
+ clearError();
+ alock.release();
+ return lockMedia();
+}
+
+STDMETHODIMP SessionMachine::UnlockMedia()
+{
+ unlockMedia();
+ return S_OK;
+}
+
STDMETHODIMP SessionMachine::EjectMedium(IMediumAttachment *aAttachment,
IMediumAttachment **aNewAttachment)
{
@@ -12815,6 +14017,7 @@ STDMETHODIMP SessionMachine::EjectMedium(IMediumAttachment *aAttachment,
// public methods only for internal purposes
/////////////////////////////////////////////////////////////////////////////
+#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER
/**
* Called from the client watcher thread to check for expected or unexpected
* death of the client process that has a direct session to this machine.
@@ -12860,47 +14063,56 @@ bool SessionMachine::checkForDeath()
Uninit::Normal :
Uninit::Abnormal;
-#if defined(RT_OS_WINDOWS)
-
- AssertMsg(mIPCSem, ("semaphore must be created"));
-
- /* release the IPC mutex */
- ::ReleaseMutex(mIPCSem);
-
- terminated = true;
+ if (mClientToken)
+ terminated = mClientToken->release();
+ } /* AutoCaller block */
-#elif defined(RT_OS_OS2)
+ if (terminated)
+ uninit(reason);
- AssertMsg(mIPCSem, ("semaphore must be created"));
+ return terminated;
+}
- /* release the IPC mutex */
- ::DosReleaseMutexSem(mIPCSem);
+void SessionMachine::getTokenId(Utf8Str &strTokenId)
+{
+ LogFlowThisFunc(("\n"));
- terminated = true;
+ strTokenId.setNull();
-#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
+ AutoCaller autoCaller(this);
+ AssertComRCReturnVoid(autoCaller.rc());
- AssertMsg(mIPCSem >= 0, ("semaphore must be created"));
+ Assert(mClientToken);
+ if (mClientToken)
+ mClientToken->getId(strTokenId);
+}
+#else /* VBOX_WITH_GENERIC_SESSION_WATCHER */
+IToken *SessionMachine::getToken()
+{
+ LogFlowThisFunc(("\n"));
- int val = ::semctl(mIPCSem, 0, GETVAL);
- if (val > 0)
- {
- /* the semaphore is signaled, meaning the session is terminated */
- terminated = true;
- }
+ AutoCaller autoCaller(this);
+ AssertComRCReturn(autoCaller.rc(), NULL);
-#else
-# error "Port me!"
-#endif
+ Assert(mClientToken);
+ if (mClientToken)
+ return mClientToken->getToken();
+ else
+ return NULL;
+}
+#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */
- } /* AutoCaller block */
+Machine::ClientToken *SessionMachine::getClientToken()
+{
+ LogFlowThisFunc(("\n"));
- if (terminated)
- uninit(reason);
+ AutoCaller autoCaller(this);
+ AssertComRCReturn(autoCaller.rc(), NULL);
- return terminated;
+ return mClientToken;
}
+
/**
* @note Locks this object for reading.
*/
@@ -13052,7 +14264,7 @@ HRESULT SessionMachine::onCPUChange(ULONG aCPU, BOOL aRemove)
LogFlowThisFunc(("\n"));
AutoCaller autoCaller(this);
- AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
+ AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
ComPtr<IInternalSessionControl> directControl;
{
@@ -13072,7 +14284,7 @@ HRESULT SessionMachine::onCPUExecutionCapChange(ULONG aExecutionCap)
LogFlowThisFunc(("\n"));
AutoCaller autoCaller(this);
- AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
+ AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
ComPtr<IInternalSessionControl> directControl;
{
@@ -13111,6 +14323,29 @@ HRESULT SessionMachine::onVRDEServerChange(BOOL aRestart)
}
/**
+ * @note Locks this object for reading.
+ */
+HRESULT SessionMachine::onVideoCaptureChange()
+{
+ LogFlowThisFunc(("\n"));
+
+ AutoCaller autoCaller(this);
+ AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
+
+ ComPtr<IInternalSessionControl> directControl;
+ {
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+ directControl = mData->mSession.mDirectControl;
+ }
+
+ /* ignore notifications sent after #OnSessionEnd() is called */
+ if (!directControl)
+ return S_OK;
+
+ return directControl->OnVideoCaptureChange();
+}
+
+/**
* @note Locks this object for reading.
*/
HRESULT SessionMachine::onUSBControllerChange()
@@ -13210,7 +14445,7 @@ HRESULT SessionMachine::onBandwidthGroupChange(IBandwidthGroup *aBandwidthGroup)
LogFlowThisFunc(("\n"));
AutoCaller autoCaller(this);
- AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
+ AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
ComPtr<IInternalSessionControl> directControl;
{
@@ -13228,7 +14463,7 @@ HRESULT SessionMachine::onBandwidthGroupChange(IBandwidthGroup *aBandwidthGroup)
/**
* @note Locks this object for reading.
*/
-HRESULT SessionMachine::onStorageDeviceChange(IMediumAttachment *aAttachment, BOOL aRemove)
+HRESULT SessionMachine::onStorageDeviceChange(IMediumAttachment *aAttachment, BOOL aRemove, BOOL aSilent)
{
LogFlowThisFunc(("\n"));
@@ -13245,7 +14480,7 @@ HRESULT SessionMachine::onStorageDeviceChange(IMediumAttachment *aAttachment, BO
if (!directControl)
return S_OK;
- return directControl->OnStorageDeviceChange(aAttachment, aRemove);
+ return directControl->OnStorageDeviceChange(aAttachment, aRemove, aSilent);
}
/**
@@ -13275,7 +14510,7 @@ bool SessionMachine::hasMatchingUSBFilter(const ComObjPtr<HostUSBDevice> &aDevic
/** @todo Live Migration: snapshoting & teleporting. Need to fend things of
* elsewhere... */
alock.release();
- return mUSBController->hasMatchingFilter(aDevice, aMaskedIfs);
+ return mUSBDeviceFilters->hasMatchingFilter(aDevice, aMaskedIfs);
default: break;
}
#else
@@ -13456,8 +14691,7 @@ void SessionMachine::releaseSavedStateFile(const Utf8Str &strStateFile,
* locked as described above; on failure no media is locked at all (all
* succeeded individual locks will be undone).
*
- * This method is intended to be called when the machine is in Starting or
- * Restoring state and asserts otherwise.
+ * The caller is responsible for doing the necessary state sanity checks.
*
* The locks made by this method must be undone by calling #unlockMedia() when
* no more needed.
@@ -13470,13 +14704,9 @@ HRESULT SessionMachine::lockMedia()
AutoMultiWriteLock2 alock(this->lockHandle(),
&mParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
- AssertReturn( mData->mMachineState == MachineState_Starting
- || mData->mMachineState == MachineState_Restoring
- || mData->mMachineState == MachineState_TeleportingIn, E_FAIL);
/* bail out if trying to lock things with already set up locking */
AssertReturn(mData->mSession.mLockedMedia.IsEmpty(), E_FAIL);
- clearError();
MultiResult mrc(S_OK);
/* Collect locking information for all medium objects attached to the VM. */
@@ -13749,13 +14979,13 @@ HRESULT SessionMachine::setMachineState(MachineState_T aMachineState)
/* Make sure any transient guest properties get removed from the
* property store on shutdown. */
- HWData::GuestPropertyList::iterator it;
+ HWData::GuestPropertyMap::const_iterator it;
BOOL fNeedsSaving = mData->mGuestPropertiesModified;
if (!fNeedsSaving)
for (it = mHWData->mGuestProperties.begin();
it != mHWData->mGuestProperties.end(); ++it)
- if ( (it->mFlags & guestProp::TRANSIENT)
- || (it->mFlags & guestProp::TRANSRESET))
+ if ( (it->second.mFlags & guestProp::TRANSIENT)
+ || (it->second.mFlags & guestProp::TRANSRESET))
{
fNeedsSaving = true;
break;
diff --git a/src/VBox/Main/src-server/MachineImplCloneVM.cpp b/src/VBox/Main/src-server/MachineImplCloneVM.cpp
index d010a04f..cdc71b82 100644
--- a/src/VBox/Main/src-server/MachineImplCloneVM.cpp
+++ b/src/VBox/Main/src-server/MachineImplCloneVM.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2011-2012 Oracle Corporation
+ * Copyright (C) 2011-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -174,11 +174,11 @@ void MachineCloneVMPrivate::updateProgressStats(MEDIUMTASKCHAIN &mtc, bool fAtta
* it. Adding the biggest size in the chain should balance this a
* little bit more, i.e. the weight is the sum of the data which
* needs to be read and written. */
- uint64_t uMaxSize = 0;
+ ULONG uMaxWeight = 0;
for (size_t e = mtc.chain.size(); e > 0; --e)
{
MEDIUMTASK &mt = mtc.chain.at(e - 1);
- mt.uWeight += uMaxSize;
+ mt.uWeight += uMaxWeight;
/* Calculate progress data */
++uCount;
@@ -186,7 +186,7 @@ void MachineCloneVMPrivate::updateProgressStats(MEDIUMTASKCHAIN &mtc, bool fAtta
/* Save the max size for better weighting of diff image
* creation. */
- uMaxSize = RT_MAX(uMaxSize, mt.uWeight);
+ uMaxWeight = RT_MAX(uMaxWeight, mt.uWeight);
}
}
}
@@ -207,7 +207,7 @@ HRESULT MachineCloneVMPrivate::addSaveState(const ComObjPtr<Machine> &machine, U
return p->setError(VBOX_E_IPRT_ERROR, p->tr("Could not query file size of '%s' (%Rrc)"), sst.strSaveStateFile.c_str(), vrc);
/* same rule as above: count both the data which needs to
* be read and written */
- sst.uWeight = 2 * (cbSize + _1M - 1) / _1M;
+ sst.uWeight = (ULONG)(2 * (cbSize + _1M - 1) / _1M);
llSaveStateFiles.append(sst);
++uCount;
uTotalWeight += sst.uWeight;
@@ -289,7 +289,7 @@ HRESULT MachineCloneVMPrivate::queryMediasForMachineState(const RTCList<ComObjPt
if (fAttachLinked)
mt.uWeight = 0; /* dummy */
else
- mt.uWeight = (lSize + _1M - 1) / _1M;
+ mt.uWeight = (ULONG)((lSize + _1M - 1) / _1M);
mtc.chain.append(mt);
/* Update the progress info. */
@@ -389,7 +389,7 @@ HRESULT MachineCloneVMPrivate::queryMediasForMachineAndChildStates(const RTCList
MEDIUMTASK mt;
mt.uIdx = UINT32_MAX;
mt.pMedium = pSrcMedium;
- mt.uWeight = (lSize + _1M - 1) / _1M;
+ mt.uWeight = (ULONG)((lSize + _1M - 1) / _1M);
mtc.chain.append(mt);
/* Query next parent. */
@@ -523,7 +523,7 @@ HRESULT MachineCloneVMPrivate::queryMediasForAllStates(const RTCList<ComObjPtr<M
MEDIUMTASK mt;
mt.uIdx = UINT32_MAX;
mt.pMedium = pSrcMedium;
- mt.uWeight = (lSize + _1M - 1) / _1M;
+ mt.uWeight = (ULONG)((lSize + _1M - 1) / _1M);
mtc.chain.append(mt);
/* Query next parent. */
@@ -950,7 +950,8 @@ HRESULT MachineCloneVM::run()
/* If we got a valid snapshot id, replace the hardware/storage section
* with the stuff from the snapshot. */
settings::Snapshot sn;
- if (!d->snapshotId.isEmpty())
+
+ if (d->snapshotId.isValid() && !d->snapshotId.isZero())
if (!d->findSnapshot(trgMCF.llFirstSnapshot, d->snapshotId, sn))
throw p->setError(E_FAIL,
p->tr("Could not find data to snapshots '%s'"), d->snapshotId.toString().c_str());
@@ -959,7 +960,7 @@ HRESULT MachineCloneVM::run()
if (d->mode == CloneMode_MachineState)
{
- if (!sn.uuid.isEmpty())
+ if (sn.uuid.isValid() && !sn.uuid.isZero())
{
trgMCF.hardwareMachine = sn.hardware;
trgMCF.storageMachine = sn.storage;
@@ -970,7 +971,8 @@ HRESULT MachineCloneVM::run()
trgMCF.uuidCurrentSnapshot.clear();
}
else if ( d->mode == CloneMode_MachineAndChildStates
- && !sn.uuid.isEmpty())
+ && sn.uuid.isValid()
+ && !sn.uuid.isZero())
{
if (!d->pOldMachineState.isNull())
{
@@ -1087,14 +1089,24 @@ HRESULT MachineCloneVM::run()
ComPtr<IMediumFormat> pSrcFormat;
rc = pMedium->COMGETTER(MediumFormat)(pSrcFormat.asOutParam());
ULONG uSrcCaps = 0;
- rc = pSrcFormat->COMGETTER(Capabilities)(&uSrcCaps);
+ com::SafeArray <MediumFormatCapabilities_T> mediumFormatCap;
+ rc = pSrcFormat->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(mediumFormatCap));
+
if (FAILED(rc)) throw rc;
+ else
+ {
+ for (ULONG j = 0; j < mediumFormatCap.size(); j++)
+ uSrcCaps |= mediumFormatCap[j];
+ }
/* Default format? */
Utf8Str strDefaultFormat;
p->mParent->getDefaultHardDiskFormat(strDefaultFormat);
Bstr bstrSrcFormat(strDefaultFormat);
+
ULONG srcVar = MediumVariant_Standard;
+ com::SafeArray <MediumVariant_T> mediumVariant;
+
/* Is the source file based? */
if ((uSrcCaps & MediumFormatCapabilities_File) == MediumFormatCapabilities_File)
{
@@ -1102,8 +1114,14 @@ HRESULT MachineCloneVM::run()
* will be used. */
rc = pMedium->COMGETTER(Format)(bstrSrcFormat.asOutParam());
if (FAILED(rc)) throw rc;
- rc = pMedium->COMGETTER(Variant)(&srcVar);
+
+ rc = pMedium->COMGETTER(Variant)(ComSafeArrayAsOutParam(mediumVariant));
if (FAILED(rc)) throw rc;
+ else
+ {
+ for (size_t j = 0; j < mediumVariant.size(); j++)
+ srcVar |= mediumVariant[j];
+ }
}
Guid newId;
@@ -1128,7 +1146,9 @@ HRESULT MachineCloneVM::run()
&& strSrcTest.endsWith("}"))
{
strSrcTest = strSrcTest.substr(1, strSrcTest.length() - 2);
- if (isValidGuid(strSrcTest))
+
+ Guid temp_guid(strSrcTest);
+ if (temp_guid.isValid() && !temp_guid.isZero())
strNewName = Utf8StrFmt("%s%s", newId.toStringCurly().c_str(), RTPathExt(strNewName.c_str()));
}
else
@@ -1322,7 +1342,7 @@ HRESULT MachineCloneVM::run()
}
/* Update the path in the configuration either for the current
* machine state or the snapshots. */
- if (sst.snapshotUuid.isEmpty())
+ if (!sst.snapshotUuid.isValid() || sst.snapshotUuid.isZero())
trgMCF.strStateFile = strTrgSaveState;
else
d->updateStateFile(trgMCF.llFirstSnapshot, sst.snapshotUuid, strTrgSaveState);
diff --git a/src/VBox/Main/src-server/Matching.cpp b/src/VBox/Main/src-server/Matching.cpp
index 83174f92..a2e0a4aa 100644
--- a/src/VBox/Main/src-server/Matching.cpp
+++ b/src/VBox/Main/src-server/Matching.cpp
@@ -36,7 +36,7 @@ void ParsedIntervalFilter_base::parse (const char *aFilter,
that->mValid = true;
that->mErrorPosition = 0;
- if (!aFilter || strncmp (aFilter, "int:", 4) != 0)
+ if (!aFilter || strncmp(aFilter, RT_STR_TUPLE("int:")) != 0)
return;
that->mNull = false;
diff --git a/src/VBox/Main/src-server/MediumAttachmentImpl.cpp b/src/VBox/Main/src-server/MediumAttachmentImpl.cpp
index 26dfeb34..6059ced6 100644
--- a/src/VBox/Main/src-server/MediumAttachmentImpl.cpp
+++ b/src/VBox/Main/src-server/MediumAttachmentImpl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -42,7 +42,8 @@ struct BackupableMediumAttachmentData
fTempEject(false),
fNonRotational(false),
fDiscard(false),
- fImplicit(false)
+ fImplicit(false),
+ fHotPluggable(false)
{ }
ComObjPtr<Medium> pMedium;
@@ -62,6 +63,7 @@ struct BackupableMediumAttachmentData
bool fNonRotational;
bool fDiscard;
bool fImplicit;
+ bool fHotPluggable;
};
struct MediumAttachment::Data
@@ -122,10 +124,11 @@ HRESULT MediumAttachment::init(Machine *aParent,
bool aTempEject,
bool aNonRotational,
bool aDiscard,
+ bool aHotPluggable,
const Utf8Str &strBandwidthGroup)
{
LogFlowThisFuncEnter();
- LogFlowThisFunc(("aParent=%p aMedium=%p aControllerName=%ls aPort=%d aDevice=%d aType=%d aImplicit=%d aPassthrough=%d aTempEject=%d aNonRotational=%d strBandwithGroup=%s\n", aParent, aMedium, aControllerName.raw(), aPort, aDevice, aType, aImplicit, aPassthrough, aTempEject, aNonRotational, strBandwidthGroup.c_str()));
+ LogFlowThisFunc(("aParent=%p aMedium=%p aControllerName=%ls aPort=%d aDevice=%d aType=%d aImplicit=%d aPassthrough=%d aTempEject=%d aNonRotational=%d aDiscard=%d aHotPluggable=%d strBandwithGroup=%s\n", aParent, aMedium, aControllerName.raw(), aPort, aDevice, aType, aImplicit, aPassthrough, aTempEject, aNonRotational, aDiscard, aHotPluggable, strBandwidthGroup.c_str()));
if (aType == DeviceType_HardDisk)
AssertReturn(aMedium, E_INVALIDARG);
@@ -151,6 +154,7 @@ HRESULT MediumAttachment::init(Machine *aParent,
m->bd->fNonRotational = aNonRotational;
m->bd->fDiscard = aDiscard;
m->bd->fImplicit = aImplicit;
+ m->bd->fHotPluggable = aHotPluggable;
/* Confirm a successful initialization when it's the case */
autoInitSpan.setSucceeded();
@@ -416,6 +420,23 @@ STDMETHODIMP MediumAttachment::COMGETTER(BandwidthGroup) (IBandwidthGroup **aBwG
return hrc;
}
+STDMETHODIMP MediumAttachment::COMGETTER(HotPluggable)(BOOL *aHotPluggable)
+{
+ LogFlowThisFuncEnter();
+
+ CheckComArgOutPointerValid(aHotPluggable);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
+
+ *aHotPluggable = m->bd->fHotPluggable;
+
+ LogFlowThisFuncLeave();
+ return S_OK;
+}
+
/**
* @note Locks this object for writing.
*/
@@ -512,6 +533,12 @@ bool MediumAttachment::getDiscard() const
return m->bd->fDiscard;
}
+bool MediumAttachment::getHotPluggable() const
+{
+ AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS);
+ return m->bd->fHotPluggable;
+}
+
const Utf8Str& MediumAttachment::getBandwidthGroup() const
{
return m->bd->strBandwidthGroup;
@@ -582,6 +609,15 @@ void MediumAttachment::updateDiscard(bool aDiscard)
m->bd->fDiscard = aDiscard;
}
+/** Must be called from under this object's write lock. */
+void MediumAttachment::updateHotPluggable(bool aHotPluggable)
+{
+ Assert(isWriteLockOnCurrentThread());
+
+ m->bd.backup();
+ m->bd->fHotPluggable = aHotPluggable;
+}
+
void MediumAttachment::updateBandwidthGroup(const Utf8Str &aBandwidthGroup)
{
LogFlowThisFuncEnter();
diff --git a/src/VBox/Main/src-server/MediumFormatImpl.cpp b/src/VBox/Main/src-server/MediumFormatImpl.cpp
index 71080e43..bd07fbf1 100644
--- a/src/VBox/Main/src-server/MediumFormatImpl.cpp
+++ b/src/VBox/Main/src-server/MediumFormatImpl.cpp
@@ -1,11 +1,11 @@
/* $Id: MediumFormatImpl.cpp $ */
/** @file
*
- * VirtualBox COM class implementation
+ * MediumFormat COM class implementation
*/
/*
- * Copyright (C) 2008-2011 Oracle Corporation
+ * Copyright (C) 2008-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -75,7 +75,7 @@ HRESULT MediumFormat::init(const VDBACKENDINFO *aVDInfo)
{
DeviceType_T devType;
- unconst(m.llFileExtensions).push_back(papExtension->pszExtension);
+ unconst(m.maFileExtensions).push_back(papExtension->pszExtension);
switch(papExtension->enmType)
{
@@ -93,7 +93,7 @@ HRESULT MediumFormat::init(const VDBACKENDINFO *aVDInfo)
return E_INVALIDARG;
}
- unconst(m.llDeviceTypes).push_back(devType);
+ unconst(m.maDeviceTypes).push_back(devType);
++papExtension;
}
}
@@ -156,7 +156,7 @@ HRESULT MediumFormat::init(const VDBACKENDINFO *aVDInfo)
dt,
flags,
defaultValue };
- unconst(m.llProperties).push_back(prop);
+ unconst(m.maProperties).push_back(prop);
++pa;
}
}
@@ -180,9 +180,9 @@ void MediumFormat::uninit()
if (autoUninitSpan.uninitDone())
return;
- unconst(m.llProperties).clear();
- unconst(m.llFileExtensions).clear();
- unconst(m.llDeviceTypes).clear();
+ unconst(m.maProperties).clear();
+ unconst(m.maFileExtensions).clear();
+ unconst(m.maDeviceTypes).clear();
unconst(m.capabilities) = (MediumFormatCapabilities_T)0;
unconst(m.strName).setNull();
unconst(m.strId).setNull();
@@ -191,129 +191,79 @@ void MediumFormat::uninit()
// IMediumFormat properties
/////////////////////////////////////////////////////////////////////////////
-STDMETHODIMP MediumFormat::COMGETTER(Id)(BSTR *aId)
+HRESULT MediumFormat::getId(com::Utf8Str &aId)
{
- CheckComArgOutPointerValid(aId);
-
- AutoCaller autoCaller(this);
- if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
/* this is const, no need to lock */
- m.strId.cloneTo(aId);
+ aId = m.strId;
return S_OK;
}
-STDMETHODIMP MediumFormat::COMGETTER(Name)(BSTR *aName)
+HRESULT MediumFormat::getName(com::Utf8Str &aName)
{
- CheckComArgOutPointerValid(aName);
-
- AutoCaller autoCaller(this);
- if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
/* this is const, no need to lock */
- m.strName.cloneTo(aName);
+ aName = m.strName;
return S_OK;
}
-STDMETHODIMP MediumFormat::COMGETTER(Capabilities)(ULONG *aCaps)
+HRESULT MediumFormat::getCapabilities(std::vector<MediumFormatCapabilities_T> &aCapabilities)
{
- CheckComArgOutPointerValid(aCaps);
-
- AutoCaller autoCaller(this);
- if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
/* m.capabilities is const, no need to lock */
- /// @todo add COMGETTER(ExtendedCapabilities) when we reach the 32 bit
- /// limit (or make the argument ULONG64 after checking that COM is capable
- /// of defining enums (used to represent bit flags) that contain 64-bit
- /// values). Or go away from the enum/ulong hack for bit sets and use
- /// a safearray like elsewhere.
- ComAssertRet((uint64_t)m.capabilities == ((ULONG)m.capabilities), E_FAIL);
-
- *aCaps = (ULONG)m.capabilities;
+ aCapabilities.resize(sizeof(MediumFormatCapabilities_T) * 8);
+ size_t cCapabilities = 0;
+ for (size_t i = 0; i < aCapabilities.size(); i++)
+ {
+ uint64_t tmp = m.capabilities;
+ tmp &= 1ULL << i;
+ if (tmp)
+ aCapabilities[cCapabilities++] = (MediumFormatCapabilities_T)tmp;
+ }
+ aCapabilities.resize(RT_MAX(cCapabilities, 1));
return S_OK;
}
-STDMETHODIMP MediumFormat::DescribeFileExtensions(ComSafeArrayOut(BSTR, aFileExtensions),
- ComSafeArrayOut(DeviceType_T, aDeviceTypes))
-{
- CheckComArgOutSafeArrayPointerValid(aFileExtensions);
-
- AutoCaller autoCaller(this);
- if (FAILED(autoCaller.rc())) return autoCaller.rc();
+// IMediumFormat methods
+/////////////////////////////////////////////////////////////////////////////
+HRESULT MediumFormat::describeFileExtensions(std::vector<com::Utf8Str> &aExtensions,
+ std::vector<DeviceType_T> &aTypes)
+{
/* this is const, no need to lock */
- com::SafeArray<BSTR> fileExtentions(m.llFileExtensions.size());
- int i = 0;
- for (StrList::const_iterator it = m.llFileExtensions.begin();
- it != m.llFileExtensions.end();
- ++it, ++i)
- (*it).cloneTo(&fileExtentions[i]);
- fileExtentions.detachTo(ComSafeArrayOutArg(aFileExtensions));
-
- com::SafeArray<DeviceType_T> deviceTypes(m.llDeviceTypes.size());
- i = 0;
- for (DeviceTypeList::const_iterator it = m.llDeviceTypes.begin();
- it != m.llDeviceTypes.end();
- ++it, ++i)
- deviceTypes[i] = (*it);
- deviceTypes.detachTo(ComSafeArrayOutArg(aDeviceTypes));
+ aExtensions = m.maFileExtensions;
+ aTypes = m.maDeviceTypes;
return S_OK;
}
-STDMETHODIMP MediumFormat::DescribeProperties(ComSafeArrayOut(BSTR, aNames),
- ComSafeArrayOut(BSTR, aDescriptions),
- ComSafeArrayOut(DataType_T, aTypes),
- ComSafeArrayOut(ULONG, aFlags),
- ComSafeArrayOut(BSTR, aDefaults))
+HRESULT MediumFormat::describeProperties(std::vector<com::Utf8Str> &aNames,
+ std::vector<com::Utf8Str> &aDescriptions,
+ std::vector<DataType_T> &aTypes,
+ std::vector<ULONG> &aFlags,
+ std::vector<com::Utf8Str> &aDefaults)
{
- CheckComArgOutSafeArrayPointerValid(aNames);
- CheckComArgOutSafeArrayPointerValid(aDescriptions);
- CheckComArgOutSafeArrayPointerValid(aTypes);
- CheckComArgOutSafeArrayPointerValid(aFlags);
- CheckComArgOutSafeArrayPointerValid(aDefaults);
-
- AutoCaller autoCaller(this);
- if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
/* this is const, no need to lock */
- size_t c = m.llProperties.size();
- com::SafeArray<BSTR> propertyNames(c);
- com::SafeArray<BSTR> propertyDescriptions(c);
- com::SafeArray<DataType_T> propertyTypes(c);
- com::SafeArray<ULONG> propertyFlags(c);
- com::SafeArray<BSTR> propertyDefaults(c);
-
- int i = 0;
- for (PropertyList::const_iterator it = m.llProperties.begin();
- it != m.llProperties.end();
- ++it, ++i)
+ size_t c = m.maProperties.size();
+ aNames.resize(c);
+ aDescriptions.resize(c);
+ aTypes.resize(c);
+ aFlags.resize(c);
+ aDefaults.resize(c);
+ for (size_t i = 0; i < c; i++)
{
- const Property &prop = (*it);
- prop.strName.cloneTo(&propertyNames[i]);
- prop.strDescription.cloneTo(&propertyDescriptions[i]);
- propertyTypes[i] = prop.type;
- propertyFlags[i] = prop.flags;
- prop.strDefaultValue.cloneTo(&propertyDefaults[i]);
+ const Property &prop = m.maProperties[i];
+ aNames[i] = prop.strName;
+ aDescriptions[i] = prop.strDescription;
+ aTypes[i] = prop.type;
+ aFlags[i] = prop.flags;
+ aDefaults[i] = prop.strDefaultValue;
}
- propertyNames.detachTo(ComSafeArrayOutArg(aNames));
- propertyDescriptions.detachTo(ComSafeArrayOutArg(aDescriptions));
- propertyTypes.detachTo(ComSafeArrayOutArg(aTypes));
- propertyFlags.detachTo(ComSafeArrayOutArg(aFlags));
- propertyDefaults.detachTo(ComSafeArrayOutArg(aDefaults));
-
return S_OK;
}
-// IMediumFormat methods
-/////////////////////////////////////////////////////////////////////////////
-
// public methods only for internal purposes
/////////////////////////////////////////////////////////////////////////////
/* vi: set tabstop=4 shiftwidth=4 expandtab: */
diff --git a/src/VBox/Main/src-server/MediumImpl.cpp b/src/VBox/Main/src-server/MediumImpl.cpp
index 64edc67f..3e5da5b3 100644
--- a/src/VBox/Main/src-server/MediumImpl.cpp
+++ b/src/VBox/Main/src-server/MediumImpl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008-2012 Oracle Corporation
+ * Copyright (C) 2008-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -16,6 +16,7 @@
*/
#include "MediumImpl.h"
+#include "TokenImpl.h"
#include "ProgressImpl.h"
#include "SystemPropertiesImpl.h"
#include "VirtualBoxImpl.h"
@@ -68,9 +69,9 @@ struct BackRef
BackRef(const Guid &aMachineId,
const Guid &aSnapshotId = Guid::Empty)
: machineId(aMachineId),
- fInCurState(aSnapshotId.isEmpty())
+ fInCurState(aSnapshotId.isZero())
{
- if (!aSnapshotId.isEmpty())
+ if (aSnapshotId.isValid() && !aSnapshotId.isZero())
llSnapshotIds.push_back(aSnapshotId);
}
@@ -514,7 +515,7 @@ public:
Medium *aTarget,
bool fMergeForward,
Medium *aParentForTarget,
- const MediaList &aChildrenToReparent,
+ MediumLockList *aChildrenToReparent,
Progress *aProgress,
MediumLockList *aMediumLockList,
bool fKeepMediumLockList = false)
@@ -522,55 +523,29 @@ public:
mTarget(aTarget),
mfMergeForward(fMergeForward),
mParentForTarget(aParentForTarget),
- mChildrenToReparent(aChildrenToReparent),
+ mpChildrenToReparent(aChildrenToReparent),
mpMediumLockList(aMediumLockList),
mTargetCaller(aTarget),
mParentForTargetCaller(aParentForTarget),
- mfChildrenCaller(false),
mfKeepMediumLockList(fKeepMediumLockList)
{
AssertReturnVoidStmt(aMediumLockList != NULL, mRC = E_FAIL);
- for (MediaList::const_iterator it = mChildrenToReparent.begin();
- it != mChildrenToReparent.end();
- ++it)
- {
- HRESULT rc2 = (*it)->addCaller();
- if (FAILED(rc2))
- {
- mRC = E_FAIL;
- for (MediaList::const_iterator it2 = mChildrenToReparent.begin();
- it2 != it;
- --it2)
- {
- (*it2)->releaseCaller();
- }
- return;
- }
- }
- mfChildrenCaller = true;
}
~MergeTask()
{
if (!mfKeepMediumLockList && mpMediumLockList)
delete mpMediumLockList;
- if (mfChildrenCaller)
- {
- for (MediaList::const_iterator it = mChildrenToReparent.begin();
- it != mChildrenToReparent.end();
- ++it)
- {
- (*it)->releaseCaller();
- }
- }
+ if (mpChildrenToReparent)
+ delete mpChildrenToReparent;
}
const ComObjPtr<Medium> mTarget;
bool mfMergeForward;
- /* When mChildrenToReparent is empty then mParentForTarget is non-null.
- * In other words: they are used in different cases. */
+ /* When mpChildrenToReparent is null then mParentForTarget is non-null and
+ * vice versa. In other words: they are used in different cases. */
const ComObjPtr<Medium> mParentForTarget;
- MediaList mChildrenToReparent;
+ MediumLockList *mpChildrenToReparent;
MediumLockList *mpMediumLockList;
private:
@@ -578,7 +553,6 @@ private:
AutoCaller mTargetCaller;
AutoCaller mParentForTargetCaller;
- bool mfChildrenCaller;
bool mfKeepMediumLockList;
};
@@ -941,7 +915,7 @@ HRESULT Medium::init(VirtualBox *aVirtualBox,
unconst(m->pVirtualBox) = aVirtualBox;
- if (!uuidMachineRegistry.isEmpty())
+ if (uuidMachineRegistry.isValid() && !uuidMachineRegistry.isZero())
m->llRegistryIDs.push_back(uuidMachineRegistry);
/* no storage yet */
@@ -958,7 +932,7 @@ HRESULT Medium::init(VirtualBox *aVirtualBox,
rc = setLocation(aLocation);
if (FAILED(rc)) return rc;
- if (!(m->formatObj->getCapabilities() & ( MediumFormatCapabilities_CreateFixed
+ if (!(m->formatObj->i_getCapabilities() & ( MediumFormatCapabilities_CreateFixed
| MediumFormatCapabilities_CreateDynamic))
)
{
@@ -973,8 +947,29 @@ HRESULT Medium::init(VirtualBox *aVirtualBox,
AutoWriteLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
ComObjPtr<Medium> pMedium;
+
+ /*
+ * Check whether the UUID is taken already and create a new one
+ * if required.
+ * Try this only a limited amount of times in case the PRNG is broken
+ * in some way to prevent an endless loop.
+ */
+ for (unsigned i = 0; i < 5; i++)
+ {
+ bool fInUse;
+
+ fInUse = m->pVirtualBox->isMediaUuidInUse(m->id, DeviceType_HardDisk);
+ if (fInUse)
+ {
+ // create new UUID
+ unconst(m->id).create();
+ }
+ else
+ break;
+ }
+
rc = m->pVirtualBox->registerMedium(this, &pMedium, DeviceType_HardDisk);
- Assert(this == pMedium);
+ Assert(this == pMedium || FAILED(rc));
}
/* Confirm a successful initialization when it's the case */
@@ -1086,7 +1081,7 @@ HRESULT Medium::init(VirtualBox *aVirtualBox,
}
else
{
- AssertStmt(!m->id.isEmpty(),
+ AssertStmt(!m->id.isZero(),
alock.release(); autoCaller.release(); uninit(); return E_FAIL);
/* storage format must be detected by Medium::queryInfo if the
@@ -1141,7 +1136,7 @@ HRESULT Medium::init(VirtualBox *aVirtualBox,
unconst(m->pVirtualBox) = aVirtualBox;
- if (!uuidMachineRegistry.isEmpty())
+ if (uuidMachineRegistry.isValid() && !uuidMachineRegistry.isZero())
m->llRegistryIDs.push_back(uuidMachineRegistry);
/* register with VirtualBox/parent early, since uninit() will
@@ -1218,7 +1213,7 @@ HRESULT Medium::init(VirtualBox *aVirtualBox,
}
Utf8Str strFull;
- if (m->formatObj->getCapabilities() & MediumFormatCapabilities_File)
+ if (m->formatObj->i_getCapabilities() & MediumFormatCapabilities_File)
{
// compose full path of the medium, if it's not fully qualified...
// slightly convoluted logic here. If the caller has given us a
@@ -1510,20 +1505,29 @@ STDMETHODIMP Medium::COMGETTER(State)(MediumState_T *aState)
return S_OK;
}
-STDMETHODIMP Medium::COMGETTER(Variant)(ULONG *aVariant)
+STDMETHODIMP Medium::COMGETTER(Variant)(ComSafeArrayOut(MediumVariant_T, aVariant))
{
- CheckComArgOutPointerValid(aVariant);
+ CheckComArgOutSafeArrayPointerValid(aVariant);
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
- *aVariant = m->variant;
+
+ SafeArray<MediumVariant_T> variants(sizeof(MediumVariant_T)*8);
+
+ for (ULONG i = 0; i < variants.size(); ++i)
+ {
+ ULONG temp = m->variant;
+ temp &= 1<<i;
+ variants [i] = (MediumVariant_T)temp;
+ }
+
+ variants.detachTo(ComSafeArrayOutArg(aVariant));
return S_OK;
}
-
STDMETHODIMP Medium::COMGETTER(Location)(BSTR *aLocation)
{
CheckComArgOutPointerValid(aLocation);
@@ -1538,27 +1542,6 @@ STDMETHODIMP Medium::COMGETTER(Location)(BSTR *aLocation)
return S_OK;
}
-STDMETHODIMP Medium::COMSETTER(Location)(IN_BSTR aLocation)
-{
- CheckComArgStrNotEmptyOrNull(aLocation);
-
- AutoCaller autoCaller(this);
- if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
- AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
- /// @todo NEWMEDIA for file names, add the default extension if no extension
- /// is present (using the information from the VD backend which also implies
- /// that one more parameter should be passed to setLocation() requesting
- /// that functionality since it is only allowed when called from this method
-
- /// @todo NEWMEDIA rename the file and set m->location on success, then save
- /// the global registry (and local registries of portable VMs referring to
- /// this medium), this will also require to add the mRegistered flag to data
-
- ReturnComNotImplemented();
-}
-
STDMETHODIMP Medium::COMGETTER(Name)(BSTR *aName)
{
CheckComArgOutPointerValid(aName);
@@ -1863,30 +1846,14 @@ STDMETHODIMP Medium::COMGETTER(LogicalSize)(LONG64 *aLogicalSize)
{
CheckComArgOutPointerValid(aLogicalSize);
- {
- AutoCaller autoCaller(this);
- if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
- /* we access mParent */
- AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
-
- AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
- if (m->pParent.isNull())
- {
- *aLogicalSize = m->logicalSize;
-
- return S_OK;
- }
- }
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
- /* We assume that some backend may decide to return a meaningless value in
- * response to VDGetSize() for differencing media and therefore always
- * ask the base medium ourselves. */
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
- /* base() will do callers/locking */
+ *aLogicalSize = m->logicalSize;
- return getBase()->COMGETTER(LogicalSize)(aLogicalSize);
+ return S_OK;
}
STDMETHODIMP Medium::COMGETTER(AutoReset)(BOOL *aAutoReset)
@@ -1999,8 +1966,8 @@ STDMETHODIMP Medium::SetIds(BOOL aSetImageId,
else
{
imageId = Guid(aImageId);
- if (imageId.isEmpty())
- return setError(E_INVALIDARG, tr("Argument %s is empty"), "aImageId");
+ if (!imageId.isValid())
+ return setError(E_INVALIDARG, tr("Argument %s is invalid"), "aImageId");
}
}
if (aSetParentId)
@@ -2060,7 +2027,7 @@ STDMETHODIMP Medium::RefreshState(MediumState_T *aState)
STDMETHODIMP Medium::GetSnapshotIds(IN_BSTR aMachineId,
ComSafeArrayOut(BSTR, aSnapshotIds))
{
- CheckComArgExpr(aMachineId, Guid(aMachineId).isEmpty() == false);
+ CheckComArgExpr(aMachineId, Guid(aMachineId).isValid());
CheckComArgOutSafeArrayPointerValid(aSnapshotIds);
AutoCaller autoCaller(this);
@@ -2108,12 +2075,10 @@ STDMETHODIMP Medium::GetSnapshotIds(IN_BSTR aMachineId,
return S_OK;
}
-/**
- * @note @a aState may be NULL if the state value is not needed (only for
- * in-process calls).
- */
-STDMETHODIMP Medium::LockRead(MediumState_T *aState)
+STDMETHODIMP Medium::LockRead(IToken **aToken)
{
+ CheckComArgNotNull(aToken);
+
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
@@ -2137,10 +2102,6 @@ STDMETHODIMP Medium::LockRead(MediumState_T *aState)
}
}
- /* return the current state before */
- if (aState)
- *aState = m->state;
-
HRESULT rc = S_OK;
switch (m->state)
@@ -2160,6 +2121,19 @@ STDMETHODIMP Medium::LockRead(MediumState_T *aState)
LogFlowThisFunc(("Okay - prev state=%d readers=%d\n", m->state, m->readers));
m->state = MediumState_LockedRead;
+ ComObjPtr<MediumLockToken> pToken;
+ rc = pToken.createObject();
+ if (SUCCEEDED(rc))
+ rc = pToken->init(this, false /* fWrite */);
+ if (FAILED(rc))
+ {
+ --m->readers;
+ if (m->readers == 0)
+ m->state = m->preLockState;
+ return rc;
+ }
+
+ pToken.queryInterfaceTo(aToken);
break;
}
default:
@@ -2177,7 +2151,7 @@ STDMETHODIMP Medium::LockRead(MediumState_T *aState)
* @note @a aState may be NULL if the state value is not needed (only for
* in-process calls).
*/
-STDMETHODIMP Medium::UnlockRead(MediumState_T *aState)
+HRESULT Medium::unlockRead(MediumState_T *aState)
{
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
@@ -2224,12 +2198,10 @@ STDMETHODIMP Medium::UnlockRead(MediumState_T *aState)
return rc;
}
-/**
- * @note @a aState may be NULL if the state value is not needed (only for
- * in-process calls).
- */
-STDMETHODIMP Medium::LockWrite(MediumState_T *aState)
+STDMETHODIMP Medium::LockWrite(IToken **aToken)
{
+ CheckComArgNotNull(aToken);
+
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
@@ -2253,10 +2225,6 @@ STDMETHODIMP Medium::LockWrite(MediumState_T *aState)
}
}
- /* return the current state before */
- if (aState)
- *aState = m->state;
-
HRESULT rc = S_OK;
switch (m->state)
@@ -2268,6 +2236,18 @@ STDMETHODIMP Medium::LockWrite(MediumState_T *aState)
LogFlowThisFunc(("Okay - prev state=%d locationFull=%s\n", m->state, getLocationFull().c_str()));
m->state = MediumState_LockedWrite;
+
+ ComObjPtr<MediumLockToken> pToken;
+ rc = pToken.createObject();
+ if (SUCCEEDED(rc))
+ rc = pToken->init(this, true /* fWrite */);
+ if (FAILED(rc))
+ {
+ m->state = m->preLockState;
+ return rc;
+ }
+
+ pToken.queryInterfaceTo(aToken);
break;
}
default:
@@ -2285,7 +2265,7 @@ STDMETHODIMP Medium::LockWrite(MediumState_T *aState)
* @note @a aState may be NULL if the state value is not needed (only for
* in-process calls).
*/
-STDMETHODIMP Medium::UnlockWrite(MediumState_T *aState)
+HRESULT Medium::unlockWrite(MediumState_T *aState)
{
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
@@ -2351,8 +2331,14 @@ STDMETHODIMP Medium::GetProperty(IN_BSTR aName, BSTR *aValue)
settings::StringsMap::const_iterator it = m->mapProperties.find(Utf8Str(aName));
if (it == m->mapProperties.end())
- return setError(VBOX_E_OBJECT_NOT_FOUND,
- tr("Property '%ls' does not exist"), aName);
+ {
+ if (!Utf8Str(aName).startsWith("Special/"))
+ return setError(VBOX_E_OBJECT_NOT_FOUND,
+ tr("Property '%ls' does not exist"), aName);
+ else
+ /* be more silent here */
+ return VBOX_E_OBJECT_NOT_FOUND;
+ }
it->second.cloneTo(aValue);
@@ -2377,13 +2363,32 @@ STDMETHODIMP Medium::SetProperty(IN_BSTR aName, IN_BSTR aValue)
return setStateError();
}
- settings::StringsMap::iterator it = m->mapProperties.find(Utf8Str(aName));
- if (it == m->mapProperties.end())
- return setError(VBOX_E_OBJECT_NOT_FOUND,
- tr("Property '%ls' does not exist"),
- aName);
-
- it->second = aValue;
+ Utf8Str strName(aName);
+ Utf8Str strValue(aValue);
+ settings::StringsMap::iterator it = m->mapProperties.find(strName);
+ if (!strName.startsWith("Special/"))
+ {
+ if (it == m->mapProperties.end())
+ return setError(VBOX_E_OBJECT_NOT_FOUND,
+ tr("Property '%s' does not exist"),
+ strName.c_str());
+ it->second = strValue;
+ }
+ else
+ {
+ if (it == m->mapProperties.end())
+ {
+ if (!strValue.isEmpty())
+ m->mapProperties[strName] = strValue;
+ }
+ else
+ {
+ if (!strValue.isEmpty())
+ it->second = aValue;
+ else
+ m->mapProperties.erase(it);
+ }
+ }
// save the settings
mlock.release();
@@ -2446,9 +2451,11 @@ STDMETHODIMP Medium::SetProperties(ComSafeArrayIn(IN_BSTR, aNames),
i < names.size();
++i)
{
- if (m->mapProperties.find(Utf8Str(names[i])) == m->mapProperties.end())
+ Utf8Str strName(names[i]);
+ if ( !strName.startsWith("Special/")
+ && m->mapProperties.find(strName) == m->mapProperties.end())
return setError(VBOX_E_OBJECT_NOT_FOUND,
- tr("Property '%ls' does not exist"), names[i]);
+ tr("Property '%s' does not exist"), strName.c_str());
}
/* second pass: assign */
@@ -2456,10 +2463,29 @@ STDMETHODIMP Medium::SetProperties(ComSafeArrayIn(IN_BSTR, aNames),
i < names.size();
++i)
{
- settings::StringsMap::iterator it = m->mapProperties.find(Utf8Str(names[i]));
- AssertReturn(it != m->mapProperties.end(), E_FAIL);
-
- it->second = Utf8Str(values[i]);
+ Utf8Str strName(names[i]);
+ Utf8Str strValue(values[i]);
+ settings::StringsMap::iterator it = m->mapProperties.find(strName);
+ if (!strName.startsWith("Special/"))
+ {
+ AssertReturn(it != m->mapProperties.end(), E_FAIL);
+ it->second = strValue;
+ }
+ else
+ {
+ if (it == m->mapProperties.end())
+ {
+ if (!strValue.isEmpty())
+ m->mapProperties[strName] = strValue;
+ }
+ else
+ {
+ if (!strValue.isEmpty())
+ it->second = strValue;
+ else
+ m->mapProperties.erase(it);
+ }
+ }
}
// save the settings
@@ -2471,9 +2497,10 @@ STDMETHODIMP Medium::SetProperties(ComSafeArrayIn(IN_BSTR, aNames),
}
STDMETHODIMP Medium::CreateBaseStorage(LONG64 aLogicalSize,
- ULONG aVariant,
+ ComSafeArrayIn(MediumVariant_T, aVariant),
IProgress **aProgress)
{
+ CheckComArgSafeArrayNotNull(aVariant);
CheckComArgOutPointerValid(aProgress);
if (aLogicalSize < 0)
return setError(E_INVALIDARG, tr("The medium size argument (%lld) is negative"), aLogicalSize);
@@ -2482,21 +2509,32 @@ STDMETHODIMP Medium::CreateBaseStorage(LONG64 aLogicalSize,
if (FAILED(autoCaller.rc())) return autoCaller.rc();
HRESULT rc = S_OK;
- ComObjPtr <Progress> pProgress;
+ ComObjPtr<Progress> pProgress;
Medium::Task *pTask = NULL;
try
{
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
- aVariant = (MediumVariant_T)((unsigned)aVariant & (unsigned)~MediumVariant_Diff);
- if ( !(aVariant & MediumVariant_Fixed)
- && !(m->formatObj->getCapabilities() & MediumFormatCapabilities_CreateDynamic))
+ ULONG mediumVariantFlags = 0;
+
+ if (aVariant)
+ {
+ com::SafeArray<MediumVariant_T> variants(ComSafeArrayInArg(aVariant));
+ for (size_t i = 0; i < variants.size(); i++)
+ mediumVariantFlags |= variants[i];
+ }
+
+ mediumVariantFlags &= ((unsigned)~MediumVariant_Diff);
+
+ if ( !(mediumVariantFlags & MediumVariant_Fixed)
+ && !(m->formatObj->i_getCapabilities() & MediumFormatCapabilities_CreateDynamic))
throw setError(VBOX_E_NOT_SUPPORTED,
tr("Medium format '%s' does not support dynamic storage creation"),
m->strFormat.c_str());
- if ( (aVariant & MediumVariant_Fixed)
- && !(m->formatObj->getCapabilities() & MediumFormatCapabilities_CreateDynamic))
+
+ if ( (mediumVariantFlags & MediumVariant_Fixed)
+ && !(m->formatObj->i_getCapabilities() & MediumFormatCapabilities_CreateDynamic))
throw setError(VBOX_E_NOT_SUPPORTED,
tr("Medium format '%s' does not support fixed storage creation"),
m->strFormat.c_str());
@@ -2507,7 +2545,7 @@ STDMETHODIMP Medium::CreateBaseStorage(LONG64 aLogicalSize,
pProgress.createObject();
rc = pProgress->init(m->pVirtualBox,
static_cast<IMedium*>(this),
- (aVariant & MediumVariant_Fixed)
+ (mediumVariantFlags & MediumVariant_Fixed)
? BstrFmt(tr("Creating fixed medium storage unit '%s'"), m->strLocationFull.c_str()).raw()
: BstrFmt(tr("Creating dynamic medium storage unit '%s'"), m->strLocationFull.c_str()).raw(),
TRUE /* aCancelable */);
@@ -2516,7 +2554,8 @@ STDMETHODIMP Medium::CreateBaseStorage(LONG64 aLogicalSize,
/* setup task object to carry out the operation asynchronously */
pTask = new Medium::CreateBaseTask(this, pProgress, aLogicalSize,
- (MediumVariant_T)aVariant);
+ (MediumVariant_T)mediumVariantFlags);
+ //(MediumVariant_T)aVariant);
rc = pTask->rc();
AssertComRC(rc);
if (FAILED(rc))
@@ -2560,11 +2599,12 @@ STDMETHODIMP Medium::DeleteStorage(IProgress **aProgress)
}
STDMETHODIMP Medium::CreateDiffStorage(IMedium *aTarget,
- ULONG aVariant,
- IProgress **aProgress)
+ ComSafeArrayIn(MediumVariant_T, aVariant),
+ IProgress **aProgress)
{
CheckComArgNotNull(aTarget);
CheckComArgOutPointerValid(aProgress);
+ CheckComArgSafeArrayNotNull(aVariant);
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
@@ -2625,9 +2665,18 @@ STDMETHODIMP Medium::CreateDiffStorage(IMedium *aTarget,
alock.release();
- ComObjPtr <Progress> pProgress;
+ ComObjPtr<Progress> pProgress;
+
+ ULONG mediumVariantFlags = 0;
+
+ if (aVariant)
+ {
+ com::SafeArray<MediumVariant_T> variants(ComSafeArrayInArg(aVariant));
+ for (size_t i = 0; i < variants.size(); i++)
+ mediumVariantFlags |= variants[i];
+ }
- rc = createDiffStorage(diff, (MediumVariant_T)aVariant, pMediumLockList,
+ rc = createDiffStorage(diff, (MediumVariant_T)mediumVariantFlags, pMediumLockList,
&pProgress, false /* aWait */);
if (FAILED(rc))
delete pMediumLockList;
@@ -2650,21 +2699,21 @@ STDMETHODIMP Medium::MergeTo(IMedium *aTarget, IProgress **aProgress)
bool fMergeForward = false;
ComObjPtr<Medium> pParentForTarget;
- MediaList childrenToReparent;
+ MediumLockList *pChildrenToReparent = NULL;
MediumLockList *pMediumLockList = NULL;
HRESULT rc = S_OK;
rc = prepareMergeTo(pTarget, NULL, NULL, true, fMergeForward,
- pParentForTarget, childrenToReparent, pMediumLockList);
+ pParentForTarget, pChildrenToReparent, pMediumLockList);
if (FAILED(rc)) return rc;
- ComObjPtr <Progress> pProgress;
+ ComObjPtr<Progress> pProgress;
- rc = mergeTo(pTarget, fMergeForward, pParentForTarget, childrenToReparent,
+ rc = mergeTo(pTarget, fMergeForward, pParentForTarget, pChildrenToReparent,
pMediumLockList, &pProgress, false /* aWait */);
if (FAILED(rc))
- cancelMergeTo(childrenToReparent, pMediumLockList);
+ cancelMergeTo(pChildrenToReparent, pMediumLockList);
else
pProgress.queryInterfaceTo(aProgress);
@@ -2672,23 +2721,29 @@ STDMETHODIMP Medium::MergeTo(IMedium *aTarget, IProgress **aProgress)
}
STDMETHODIMP Medium::CloneToBase(IMedium *aTarget,
- ULONG aVariant,
- IProgress **aProgress)
+ ComSafeArrayIn(MediumVariant_T, aVariant),
+ IProgress **aProgress)
{
int rc = S_OK;
CheckComArgNotNull(aTarget);
CheckComArgOutPointerValid(aProgress);
- rc = CloneTo(aTarget, aVariant, NULL, aProgress);
+ CheckComArgSafeArrayNotNull(aVariant);
+
+ com::SafeArray<MediumVariant_T> variants(ComSafeArrayInArg(aVariant));
+
+ rc = CloneTo(aTarget, ComSafeArrayAsInParam(variants), NULL, aProgress);
return rc;
}
STDMETHODIMP Medium::CloneTo(IMedium *aTarget,
- ULONG aVariant,
+ ComSafeArrayIn(MediumVariant_T, aVariant),
IMedium *aParent,
IProgress **aProgress)
{
CheckComArgNotNull(aTarget);
CheckComArgOutPointerValid(aProgress);
+ CheckComArgSafeArrayNotNull(aVariant);
+
ComAssertRet(aTarget != this, E_INVALIDARG);
AutoCaller autoCaller(this);
@@ -2786,9 +2841,18 @@ STDMETHODIMP Medium::CloneTo(IMedium *aTarget,
throw rc;
}
+ ULONG mediumVariantFlags = 0;
+
+ if (aVariant)
+ {
+ com::SafeArray<MediumVariant_T> variants(ComSafeArrayInArg(aVariant));
+ for (size_t i = 0; i < variants.size(); i++)
+ mediumVariantFlags |= variants[i];
+ }
+
/* setup task object to carry out the operation asynchronously */
pTask = new Medium::CloneTask(this, pProgress, pTarget,
- (MediumVariant_T)aVariant,
+ (MediumVariant_T)mediumVariantFlags,
pParent, UINT32_MAX, UINT32_MAX,
pSourceMediumLockList, pTargetMediumLockList);
rc = pTask->rc();
@@ -2814,6 +2878,29 @@ STDMETHODIMP Medium::CloneTo(IMedium *aTarget,
return rc;
}
+STDMETHODIMP Medium::SetLocation(IN_BSTR aLocation, IProgress **aProgress)
+{
+ CheckComArgStrNotEmptyOrNull(aLocation);
+ CheckComArgOutPointerValid(aProgress);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ /// @todo NEWMEDIA for file names, add the default extension if no extension
+ /// is present (using the information from the VD backend which also implies
+ /// that one more parameter should be passed to setLocation() requesting
+ /// that functionality since it is only allowed when called from this method
+
+ /// @todo NEWMEDIA rename the file and set m->location on success, then save
+ /// the global registry (and local registries of portable VMs referring to
+ /// this medium), this will also require to add the mRegistered flag to data
+
+ *aProgress = NULL;
+ ReturnComNotImplemented();
+}
+
STDMETHODIMP Medium::Compact(IProgress **aProgress)
{
CheckComArgOutPointerValid(aProgress);
@@ -2822,7 +2909,7 @@ STDMETHODIMP Medium::Compact(IProgress **aProgress)
if (FAILED(autoCaller.rc())) return autoCaller.rc();
HRESULT rc = S_OK;
- ComObjPtr <Progress> pProgress;
+ ComObjPtr<Progress> pProgress;
Medium::Task *pTask = NULL;
try
@@ -2895,7 +2982,7 @@ STDMETHODIMP Medium::Resize(LONG64 aLogicalSize, IProgress **aProgress)
if (FAILED(autoCaller.rc())) return autoCaller.rc();
HRESULT rc = S_OK;
- ComObjPtr <Progress> pProgress;
+ ComObjPtr<Progress> pProgress;
Medium::Task *pTask = NULL;
try
@@ -2968,7 +3055,7 @@ STDMETHODIMP Medium::Reset(IProgress **aProgress)
if (FAILED(autoCaller.rc())) return autoCaller.rc();
HRESULT rc = S_OK;
- ComObjPtr <Progress> pProgress;
+ ComObjPtr<Progress> pProgress;
Medium::Task *pTask = NULL;
try
@@ -3038,17 +3125,8 @@ STDMETHODIMP Medium::Reset(IProgress **aProgress)
if (SUCCEEDED(rc))
pProgress.queryInterfaceTo(aProgress);
}
- else
- {
- /* Note: on success, the task will unlock this */
- {
- AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
- HRESULT rc2 = UnlockWrite(NULL);
- AssertComRC(rc2);
- }
- if (pTask != NULL)
- delete pTask;
- }
+ else if (pTask != NULL)
+ delete pTask;
LogFlowThisFunc(("LEAVE, rc=%Rhrc\n", rc));
@@ -3150,7 +3228,7 @@ const ComObjPtr<MediumFormat>& Medium::getMediumFormat() const
bool Medium::isMediumFormatFile() const
{
if ( m->formatObj
- && (m->formatObj->getCapabilities() & MediumFormatCapabilities_File)
+ && (m->formatObj->i_getCapabilities() & MediumFormatCapabilities_File)
)
return true;
return false;
@@ -3382,6 +3460,9 @@ void Medium::markRegistriesModified()
llRegistryIDs = m->llRegistryIDs;
}
+ /* Save the error information now, the implicit restore when this goes
+ * out of scope will throw away spurious additional errors created below. */
+ ErrorInfoKeeper eik;
for (GuidList::const_iterator it = llRegistryIDs.begin();
it != llRegistryIDs.end();
++it)
@@ -3400,7 +3481,7 @@ void Medium::markRegistriesModified()
HRESULT Medium::addBackReference(const Guid &aMachineId,
const Guid &aSnapshotId /*= Guid::Empty*/)
{
- AssertReturn(!aMachineId.isEmpty(), E_FAIL);
+ AssertReturn(aMachineId.isValid(), E_FAIL);
LogFlowThisFunc(("ENTER, aMachineId: {%RTuuid}, aSnapshotId: {%RTuuid}\n", aMachineId.raw(), aSnapshotId.raw()));
@@ -3442,7 +3523,8 @@ HRESULT Medium::addBackReference(const Guid &aMachineId,
// if the caller has not supplied a snapshot ID, then we're attaching
// to a machine a medium which represents the machine's current state,
// so set the flag
- if (aSnapshotId.isEmpty())
+
+ if (aSnapshotId.isZero())
{
/* sanity: no duplicate attachments */
if (it->fInCurState)
@@ -3479,7 +3561,8 @@ HRESULT Medium::addBackReference(const Guid &aMachineId,
}
it->llSnapshotIds.push_back(aSnapshotId);
- it->fInCurState = false;
+ // Do not touch fInCurState, as the image may be attached to the current
+ // state *and* a snapshot, otherwise we lose the current state association!
LogFlowThisFuncLeave();
@@ -3497,7 +3580,7 @@ HRESULT Medium::addBackReference(const Guid &aMachineId,
HRESULT Medium::removeBackReference(const Guid &aMachineId,
const Guid &aSnapshotId /*= Guid::Empty*/)
{
- AssertReturn(!aMachineId.isEmpty(), E_FAIL);
+ AssertReturn(aMachineId.isValid(), E_FAIL);
AutoCaller autoCaller(this);
AssertComRCReturnRC(autoCaller.rc());
@@ -3509,7 +3592,7 @@ HRESULT Medium::removeBackReference(const Guid &aMachineId,
BackRef::EqualsTo(aMachineId));
AssertReturn(it != m->backRefs.end(), E_FAIL);
- if (aSnapshotId.isEmpty())
+ if (aSnapshotId.isZero())
{
/* remove the current state attachment */
it->fInCurState = false;
@@ -4091,7 +4174,7 @@ Utf8Str Medium::getPreferredDiffFormat()
AssertComRCReturn(autoCaller.rc(), Utf8Str::Empty);
/* check that our own format supports diffs */
- if (!(m->formatObj->getCapabilities() & MediumFormatCapabilities_Differencing))
+ if (!(m->formatObj->i_getCapabilities() & MediumFormatCapabilities_Differencing))
{
/* use the default format if not */
Utf8Str tmp;
@@ -4224,7 +4307,7 @@ HRESULT Medium::deleteStorage(ComObjPtr<Progress> *aProgress,
COMMA_LOCKVAL_SRC_POS);
LogFlowThisFunc(("aWait=%RTbool locationFull=%s\n", aWait, getLocationFull().c_str() ));
- if ( !(m->formatObj->getCapabilities() & ( MediumFormatCapabilities_CreateDynamic
+ if ( !(m->formatObj->i_getCapabilities() & ( MediumFormatCapabilities_CreateDynamic
| MediumFormatCapabilities_CreateFixed)))
throw setError(VBOX_E_NOT_SUPPORTED,
tr("Medium format '%s' does not support storage deletion"),
@@ -4451,6 +4534,112 @@ HRESULT Medium::unmarkLockedForDeletion()
}
/**
+ * Queries the preferred merge direction from this to the other medium, i.e.
+ * the one which requires the least amount of I/O and therefore time and
+ * disk consumption.
+ *
+ * @returns Status code.
+ * @retval E_FAIL in case determining the merge direction fails for some reason,
+ * for example if getting the size of the media fails. There is no
+ * error set though and the caller is free to continue to find out
+ * what was going wrong later. Leaves fMergeForward unset.
+ * @retval VBOX_E_INVALID_OBJECT_STATE if both media are not related to each other
+ * An error is set.
+ * @param pOther The other medium to merge with.
+ * @param fMergeForward Resulting preferred merge direction (out).
+ */
+HRESULT Medium::queryPreferredMergeDirection(const ComObjPtr<Medium> &pOther,
+ bool &fMergeForward)
+{
+ AssertReturn(pOther != NULL, E_FAIL);
+ AssertReturn(pOther != this, E_FAIL);
+
+ AutoCaller autoCaller(this);
+ AssertComRCReturnRC(autoCaller.rc());
+
+ AutoCaller otherCaller(pOther);
+ AssertComRCReturnRC(otherCaller.rc());
+
+ HRESULT rc = S_OK;
+ bool fThisParent = false; /**<< Flag whether this medium is the parent of pOther. */
+
+ try
+ {
+ // locking: we need the tree lock first because we access parent pointers
+ AutoWriteLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
+
+ /* more sanity checking and figuring out the current merge direction */
+ ComObjPtr<Medium> pMedium = getParent();
+ while (!pMedium.isNull() && pMedium != pOther)
+ pMedium = pMedium->getParent();
+ if (pMedium == pOther)
+ fThisParent = false;
+ else
+ {
+ pMedium = pOther->getParent();
+ while (!pMedium.isNull() && pMedium != this)
+ pMedium = pMedium->getParent();
+ if (pMedium == this)
+ fThisParent = true;
+ else
+ {
+ Utf8Str tgtLoc;
+ {
+ AutoReadLock alock(pOther COMMA_LOCKVAL_SRC_POS);
+ tgtLoc = pOther->getLocationFull();
+ }
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+ throw setError(VBOX_E_INVALID_OBJECT_STATE,
+ tr("Media '%s' and '%s' are unrelated"),
+ m->strLocationFull.c_str(), tgtLoc.c_str());
+ }
+ }
+
+ /*
+ * Figure out the preferred merge direction. The current way is to
+ * get the current sizes of file based images and select the merge
+ * direction depending on the size.
+ *
+ * Can't use the VD API to get current size here as the media might
+ * be write locked by a running VM. Resort to RTFileQuerySize().
+ */
+ int vrc = VINF_SUCCESS;
+ uint64_t cbMediumThis = 0;
+ uint64_t cbMediumOther = 0;
+
+ if (isMediumFormatFile() && pOther->isMediumFormatFile())
+ {
+ vrc = RTFileQuerySize(this->getLocationFull().c_str(), &cbMediumThis);
+ if (RT_SUCCESS(vrc))
+ {
+ vrc = RTFileQuerySize(pOther->getLocationFull().c_str(),
+ &cbMediumOther);
+ }
+
+ if (RT_FAILURE(vrc))
+ rc = E_FAIL;
+ else
+ {
+ /*
+ * Check which merge direction might be more optimal.
+ * This method is not bullet proof of course as there might
+ * be overlapping blocks in the images so the file size is
+ * not the best indicator but it is good enough for our purpose
+ * and everything else is too complicated, especially when the
+ * media are used by a running VM.
+ */
+ bool fMergeIntoThis = cbMediumThis > cbMediumOther;
+ fMergeForward = fMergeIntoThis ^ fThisParent;
+ }
+ }
+ }
+ catch (HRESULT aRC) { rc = aRC; }
+
+ return rc;
+}
+
+/**
* Prepares this (source) medium, target medium and all intermediate media
* for the merge operation.
*
@@ -4470,8 +4659,9 @@ HRESULT Medium::unmarkLockedForDeletion()
* later you must call #cancelMergeTo().
* @param fMergeForward Resulting merge direction (out).
* @param pParentForTarget New parent for target medium after merge (out).
- * @param aChildrenToReparent List of children of the source which will have
- * to be reparented to the target after merge (out).
+ * @param aChildrenToReparent Medium lock list containing all children of the
+ * source which will have to be reparented to the target
+ * after merge (out).
* @param aMediumLockList Medium locking information (out).
*
* @note Locks medium tree for reading. Locks this object, aTarget and all
@@ -4483,7 +4673,7 @@ HRESULT Medium::prepareMergeTo(const ComObjPtr<Medium> &pTarget,
bool fLockMedia,
bool &fMergeForward,
ComObjPtr<Medium> &pParentForTarget,
- MediaList &aChildrenToReparent,
+ MediumLockList * &aChildrenToReparent,
MediumLockList * &aMediumLockList)
{
AssertReturn(pTarget != NULL, E_FAIL);
@@ -4498,7 +4688,8 @@ HRESULT Medium::prepareMergeTo(const ComObjPtr<Medium> &pTarget,
HRESULT rc = S_OK;
fMergeForward = false;
pParentForTarget.setNull();
- aChildrenToReparent.clear();
+ Assert(aChildrenToReparent == NULL);
+ aChildrenToReparent = NULL;
Assert(aMediumLockList == NULL);
aMediumLockList = NULL;
@@ -4587,9 +4778,9 @@ HRESULT Medium::prepareMergeTo(const ComObjPtr<Medium> &pTarget,
if ( m->backRefs.size() != 0
&& ( !aMachineId
|| m->backRefs.size() != 1
- || aMachineId->isEmpty()
+ || aMachineId->isZero()
|| *getFirstMachineBackrefId() != *aMachineId
- || ( (!aSnapshotId || !aSnapshotId->isEmpty())
+ || ( (!aSnapshotId || !aSnapshotId->isZero())
&& *getFirstMachineBackrefSnapshotId() != *aSnapshotId)))
throw setError(VBOX_E_OBJECT_IN_USE,
tr("Medium '%s' is attached to %d virtual machines"),
@@ -4681,19 +4872,21 @@ HRESULT Medium::prepareMergeTo(const ComObjPtr<Medium> &pTarget,
else
{
/* we will need to reparent children of the source */
+ aChildrenToReparent = new MediumLockList();
for (MediaList::const_iterator it = getChildren().begin();
it != getChildren().end();
++it)
{
pMedium = *it;
- if (fLockMedia)
- {
- rc = pMedium->LockWrite(NULL);
- if (FAILED(rc))
- throw rc;
- }
-
- aChildrenToReparent.push_back(pMedium);
+ aChildrenToReparent->Append(pMedium, true /* fLockWrite */);
+ }
+ if (fLockMedia && aChildrenToReparent)
+ {
+ treeLock.release();
+ rc = aChildrenToReparent->Lock();
+ treeLock.acquire();
+ if (FAILED(rc))
+ throw rc;
}
}
for (pLast = pLastIntermediate;
@@ -4752,8 +4945,16 @@ HRESULT Medium::prepareMergeTo(const ComObjPtr<Medium> &pTarget,
if (FAILED(rc))
{
- delete aMediumLockList;
- aMediumLockList = NULL;
+ if (aMediumLockList)
+ {
+ delete aMediumLockList;
+ aMediumLockList = NULL;
+ }
+ if (aChildrenToReparent)
+ {
+ delete aChildrenToReparent;
+ aChildrenToReparent = NULL;
+ }
}
return rc;
@@ -4838,9 +5039,9 @@ HRESULT Medium::prepareMergeTo(const ComObjPtr<Medium> &pTarget,
HRESULT Medium::mergeTo(const ComObjPtr<Medium> &pTarget,
bool fMergeForward,
const ComObjPtr<Medium> &pParentForTarget,
- const MediaList &aChildrenToReparent,
+ MediumLockList *aChildrenToReparent,
MediumLockList *aMediumLockList,
- ComObjPtr <Progress> *aProgress,
+ ComObjPtr<Progress> *aProgress,
bool aWait)
{
AssertReturn(pTarget != NULL, E_FAIL);
@@ -4855,7 +5056,7 @@ HRESULT Medium::mergeTo(const ComObjPtr<Medium> &pTarget,
AssertComRCReturnRC(targetCaller.rc());
HRESULT rc = S_OK;
- ComObjPtr <Progress> pProgress;
+ ComObjPtr<Progress> pProgress;
Medium::Task *pTask = NULL;
try
@@ -4927,7 +5128,7 @@ HRESULT Medium::mergeTo(const ComObjPtr<Medium> &pTarget,
*
* @note Locks the media from the chain for writing.
*/
-void Medium::cancelMergeTo(const MediaList &aChildrenToReparent,
+void Medium::cancelMergeTo(MediumLockList *aChildrenToReparent,
MediumLockList *aMediumLockList)
{
AutoCaller autoCaller(this);
@@ -4959,23 +5160,17 @@ void Medium::cancelMergeTo(const MediaList &aChildrenToReparent,
/* the destructor will do the work */
delete aMediumLockList;
- /* unlock the children which had to be reparented */
- for (MediaList::const_iterator it = aChildrenToReparent.begin();
- it != aChildrenToReparent.end();
- ++it)
- {
- const ComObjPtr<Medium> &pMedium = *it;
-
- AutoWriteLock alock(pMedium COMMA_LOCKVAL_SRC_POS);
- pMedium->UnlockWrite(NULL);
- }
+ /* unlock the children which had to be reparented, the destructor will do
+ * the work */
+ if (aChildrenToReparent)
+ delete aChildrenToReparent;
}
/**
* Fix the parent UUID of all children to point to this medium as their
* parent.
*/
-HRESULT Medium::fixParentUuidOfChildren(const MediaList &childrenToReparent)
+HRESULT Medium::fixParentUuidOfChildren(MediumLockList *pChildrenToReparent)
{
Assert(!isWriteLockOnCurrentThread());
Assert(!m->pVirtualBox->getMediaTreeLockHandle().isWriteLockOnCurrentThread());
@@ -5016,16 +5211,19 @@ HRESULT Medium::fixParentUuidOfChildren(const MediaList &childrenToReparent)
throw vrc;
}
- for (MediaList::const_iterator it = childrenToReparent.begin();
- it != childrenToReparent.end();
+ MediumLockList::Base::iterator childrenBegin = pChildrenToReparent->GetBegin();
+ MediumLockList::Base::iterator childrenEnd = pChildrenToReparent->GetEnd();
+ for (MediumLockList::Base::iterator it = childrenBegin;
+ it != childrenEnd;
++it)
{
+ Medium *pMedium = it->GetMedium();
/* VD_OPEN_FLAGS_INFO since UUID is wrong yet */
vrc = VDOpen(hdd,
- (*it)->m->strFormat.c_str(),
- (*it)->m->strLocationFull.c_str(),
+ pMedium->m->strFormat.c_str(),
+ pMedium->m->strLocationFull.c_str(),
VD_OPEN_FLAGS_INFO | m->uOpenFlagsDef,
- (*it)->m->vdImageIfaces);
+ pMedium->m->vdImageIfaces);
if (RT_FAILURE(vrc))
throw vrc;
@@ -5036,8 +5234,6 @@ HRESULT Medium::fixParentUuidOfChildren(const MediaList &childrenToReparent)
vrc = VDClose(hdd, false /* fDelete */);
if (RT_FAILURE(vrc))
throw vrc;
-
- (*it)->UnlockWrite(NULL);
}
}
catch (HRESULT aRC) { rc = aRC; }
@@ -5433,7 +5629,7 @@ HRESULT Medium::queryInfo(bool fSetImageId, bool fSetParentId)
/* are we dealing with a new medium constructed using the existing
* location? */
- bool isImport = m->id.isEmpty();
+ bool isImport = m->id.isZero();
unsigned uOpenFlags = VD_OPEN_FLAGS_INFO;
/* Note that we don't use VD_OPEN_FLAGS_READONLY when opening new
@@ -5453,10 +5649,11 @@ HRESULT Medium::queryInfo(bool fSetImageId, bool fSetParentId)
/* Lock the medium, which makes the behavior much more consistent */
alock.release();
+ ComPtr<IToken> pToken;
if (uOpenFlags & (VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_SHAREABLE))
- rc = LockRead(NULL);
+ rc = LockRead(pToken.asOutParam());
else
- rc = LockWrite(NULL);
+ rc = LockWrite(pToken.asOutParam());
if (FAILED(rc)) return rc;
alock.acquire();
@@ -5524,7 +5721,7 @@ HRESULT Medium::queryInfo(bool fSetImageId, bool fSetParentId)
throw S_OK;
}
- if (formatObj->getCapabilities() & MediumFormatCapabilities_Uuid)
+ if (formatObj->i_getCapabilities() & MediumFormatCapabilities_Uuid)
{
/* Modify the UUIDs if necessary. The associated fields are
* not modified by other code, so no need to copy. */
@@ -5533,7 +5730,12 @@ HRESULT Medium::queryInfo(bool fSetImageId, bool fSetParentId)
alock.acquire();
vrc = VDSetUuid(hdd, 0, m->uuidImage.raw());
alock.release();
- ComAssertRCThrow(vrc, E_FAIL);
+ if (RT_FAILURE(vrc))
+ {
+ lastAccessError = Utf8StrFmt(tr("Could not update the UUID of medium '%s'%s"),
+ location.c_str(), vdError(vrc).c_str());
+ throw S_OK;
+ }
mediumId = m->uuidImage;
}
if (fSetParentId)
@@ -5541,7 +5743,12 @@ HRESULT Medium::queryInfo(bool fSetImageId, bool fSetParentId)
alock.acquire();
vrc = VDSetParentUuid(hdd, 0, m->uuidParentImage.raw());
alock.release();
- ComAssertRCThrow(vrc, E_FAIL);
+ if (RT_FAILURE(vrc))
+ {
+ lastAccessError = Utf8StrFmt(tr("Could not update the parent UUID of medium '%s'%s"),
+ location.c_str(), vdError(vrc).c_str());
+ throw S_OK;
+ }
}
/* zap the information, these are no long-term members */
alock.acquire();
@@ -5558,13 +5765,13 @@ HRESULT Medium::queryInfo(bool fSetImageId, bool fSetParentId)
{
mediumId = uuid;
- if (mediumId.isEmpty() && (m->hddOpenMode == OpenReadOnly))
+ if (mediumId.isZero() && (m->hddOpenMode == OpenReadOnly))
// only when importing a VDMK that has no UUID, create one in memory
mediumId.create();
}
else
{
- Assert(!mediumId.isEmpty());
+ Assert(!mediumId.isZero());
if (mediumId != uuid)
{
@@ -5626,7 +5833,7 @@ HRESULT Medium::queryInfo(bool fSetImageId, bool fSetParentId)
* Since such images don't support random writes they will not
* be created for diff images. Only an overly smart user might
* manually create this case. Too bad for him. */
- if ( isImport
+ if ( (isImport || fSetParentId)
&& !(uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
{
/* the parent must be known to us. Note that we freely
@@ -5636,24 +5843,43 @@ HRESULT Medium::queryInfo(bool fSetImageId, bool fSetParentId)
* threads yet (and init() will fail if this method reports
* MediumState_Inaccessible) */
- Guid id = parentId;
ComObjPtr<Medium> pParent;
- rc = m->pVirtualBox->findHardDiskById(id, false /* aSetError */, &pParent);
+ if (RTUuidIsNull(&parentId))
+ rc = VBOX_E_OBJECT_NOT_FOUND;
+ else
+ rc = m->pVirtualBox->findHardDiskById(Guid(parentId), false /* aSetError */, &pParent);
if (FAILED(rc))
{
- lastAccessError = Utf8StrFmt(
- tr("Parent medium with UUID {%RTuuid} of the medium '%s' is not found in the media registry ('%s')"),
- &parentId, location.c_str(),
- m->pVirtualBox->settingsFilePath().c_str());
- throw S_OK;
+ if (fSetImageId && !fSetParentId)
+ {
+ /* If the image UUID gets changed for an existing
+ * image then the parent UUID can be stale. In such
+ * cases clear the parent information. The parent
+ * information may/will be re-set later if the
+ * API client wants to adjust a complete medium
+ * hierarchy one by one. */
+ rc = S_OK;
+ alock.acquire();
+ RTUuidClear(&parentId);
+ vrc = VDSetParentUuid(hdd, 0, &parentId);
+ alock.release();
+ ComAssertRCThrow(vrc, E_FAIL);
+ }
+ else
+ {
+ lastAccessError = Utf8StrFmt(tr("Parent medium with UUID {%RTuuid} of the medium '%s' is not found in the media registry ('%s')"),
+ &parentId, location.c_str(),
+ m->pVirtualBox->settingsFilePath().c_str());
+ throw S_OK;
+ }
}
/* we set mParent & children() */
treeLock.acquire();
- Assert(m->pParent.isNull());
- m->pParent = pParent;
- m->pParent->m->llChildren.push_back(this);
+ if (m->pParent)
+ deparent();
+ setParent(pParent);
treeLock.release();
}
@@ -5765,13 +5991,9 @@ HRESULT Medium::queryInfo(bool fSetImageId, bool fSetParentId)
else
m->preLockState = MediumState_Inaccessible;
- HRESULT rc2;
- if (uOpenFlags & (VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_SHAREABLE))
- rc2 = UnlockRead(NULL);
- else
- rc2 = UnlockWrite(NULL);
- if (SUCCEEDED(rc) && FAILED(rc2))
- rc = rc2;
+ pToken->Abandon();
+ pToken.setNull();
+
if (FAILED(rc)) return rc;
/* If this is a base image which incorrectly has a parent UUID set,
@@ -5782,7 +6004,7 @@ HRESULT Medium::queryInfo(bool fSetImageId, bool fSetParentId)
* the diff. Not acceptable. */
if (fRepairImageZeroParentUuid)
{
- rc = LockWrite(NULL);
+ rc = LockWrite(pToken.asOutParam());
if (FAILED(rc)) return rc;
alock.release();
@@ -5820,9 +6042,8 @@ HRESULT Medium::queryInfo(bool fSetImageId, bool fSetParentId)
rc = aRC;
}
- rc = UnlockWrite(NULL);
- if (SUCCEEDED(rc) && FAILED(rc2))
- rc = rc2;
+ pToken->Abandon();
+ pToken.setNull();
if (FAILED(rc)) return rc;
}
@@ -6013,7 +6234,7 @@ HRESULT Medium::setLocation(const Utf8Str &aLocation,
AssertReturn( (!m->strFormat.isEmpty() && !m->formatObj.isNull())
|| ( autoCaller.state() == InInit
&& m->state != MediumState_NotCreated
- && m->id.isEmpty()
+ && m->id.isZero()
&& m->strFormat.isEmpty()
&& m->formatObj.isNull()),
E_FAIL);
@@ -6023,7 +6244,7 @@ HRESULT Medium::setLocation(const Utf8Str &aLocation,
bool isImport = m->strFormat.isEmpty();
if ( isImport
- || ( (m->formatObj->getCapabilities() & MediumFormatCapabilities_File)
+ || ( (m->formatObj->i_getCapabilities() & MediumFormatCapabilities_File)
&& !m->hostDrive))
{
Guid id;
@@ -6033,7 +6254,7 @@ HRESULT Medium::setLocation(const Utf8Str &aLocation,
if (m->state == MediumState_NotCreated)
{
/* must be a file (formatObj must be already known) */
- Assert(m->formatObj->getCapabilities() & MediumFormatCapabilities_File);
+ Assert(m->formatObj->i_getCapabilities() & MediumFormatCapabilities_File);
if (RTPathFilename(aLocation.c_str()) == NULL)
{
@@ -6041,11 +6262,11 @@ HRESULT Medium::setLocation(const Utf8Str &aLocation,
* slash), generate a new UUID + file name if the state allows
* this */
- ComAssertMsgRet(!m->formatObj->getFileExtensions().empty(),
+ ComAssertMsgRet(!m->formatObj->i_getFileExtensions().empty(),
("Must be at least one extension if it is MediumFormatCapabilities_File\n"),
E_FAIL);
- Utf8Str strExt = m->formatObj->getFileExtensions().front();
+ Utf8Str strExt = m->formatObj->i_getFileExtensions().front();
ComAssertMsgRet(!strExt.isEmpty(),
("Default extension must not be empty\n"),
E_FAIL);
@@ -6059,7 +6280,7 @@ HRESULT Medium::setLocation(const Utf8Str &aLocation,
// we must always have full paths now (if it refers to a file)
if ( ( m->formatObj.isNull()
- || m->formatObj->getCapabilities() & MediumFormatCapabilities_File)
+ || m->formatObj->i_getCapabilities() & MediumFormatCapabilities_File)
&& !RTPathStartsWithRoot(locationFull.c_str()))
return setError(VBOX_E_FILE_ERROR,
tr("The given path '%s' is not fully qualified"),
@@ -6145,7 +6366,7 @@ HRESULT Medium::setLocation(const Utf8Str &aLocation,
m->strLocationFull = locationFull;
/* is it still a file? */
- if ( (m->formatObj->getCapabilities() & MediumFormatCapabilities_File)
+ if ( (m->formatObj->i_getCapabilities() & MediumFormatCapabilities_File)
&& (m->state == MediumState_NotCreated)
)
/* assign a new UUID (this UUID will be used when calling
@@ -6193,8 +6414,8 @@ HRESULT Medium::setFormat(const Utf8Str &aFormat)
Assert(m->mapProperties.empty());
- for (MediumFormat::PropertyList::const_iterator it = m->formatObj->getProperties().begin();
- it != m->formatObj->getProperties().end();
+ for (MediumFormat::PropertyArray::const_iterator it = m->formatObj->i_getProperties().begin();
+ it != m->formatObj->i_getProperties().end();
++it)
{
m->mapProperties.insert(std::make_pair(it->strName, Utf8Str::Empty));
@@ -6572,7 +6793,8 @@ HRESULT Medium::taskCreateBaseHandler(Medium::CreateBaseTask &task)
/* The object may request a specific UUID (through a special form of
* the setLocation() argument). Otherwise we have to generate it */
Guid id = m->id;
- fGenerateUuid = id.isEmpty();
+
+ fGenerateUuid = id.isZero();
if (fGenerateUuid)
{
id.create();
@@ -6582,7 +6804,7 @@ HRESULT Medium::taskCreateBaseHandler(Medium::CreateBaseTask &task)
Utf8Str format(m->strFormat);
Utf8Str location(m->strLocationFull);
- uint64_t capabilities = m->formatObj->getCapabilities();
+ uint64_t capabilities = m->formatObj->i_getCapabilities();
ComAssertThrow(capabilities & ( MediumFormatCapabilities_CreateFixed
| MediumFormatCapabilities_CreateDynamic), E_FAIL);
Assert(m->state == MediumState_Creating);
@@ -6709,7 +6931,8 @@ HRESULT Medium::taskCreateDiffHandler(Medium::CreateDiffTask &task)
/* The object may request a specific UUID (through a special form of
* the setLocation() argument). Otherwise we have to generate it */
Guid targetId = pTarget->m->id;
- fGenerateUuid = targetId.isEmpty();
+
+ fGenerateUuid = targetId.isZero();
if (fGenerateUuid)
{
targetId.create();
@@ -6721,7 +6944,7 @@ HRESULT Medium::taskCreateDiffHandler(Medium::CreateDiffTask &task)
Utf8Str targetFormat(pTarget->m->strFormat);
Utf8Str targetLocation(pTarget->m->strLocationFull);
- uint64_t capabilities = pTarget->m->formatObj->getCapabilities();
+ uint64_t capabilities = pTarget->m->formatObj->i_getCapabilities();
ComAssertThrow(capabilities & MediumFormatCapabilities_CreateDynamic, E_FAIL);
Assert(pTarget->m->state == MediumState_Creating);
@@ -6762,7 +6985,7 @@ HRESULT Medium::taskCreateDiffHandler(Medium::CreateDiffTask &task)
vrc = VDOpen(hdd,
pMedium->m->strFormat.c_str(),
pMedium->m->strLocationFull.c_str(),
- VD_OPEN_FLAGS_READONLY | m->uOpenFlagsDef,
+ VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO | m->uOpenFlagsDef,
pMedium->m->vdImageIfaces);
if (RT_FAILURE(vrc))
throw setError(VBOX_E_FILE_ERROR,
@@ -6988,18 +7211,21 @@ HRESULT Medium::taskMergeHandler(Medium::MergeTask &task)
/* we need to update UUIDs of all source's children
* which cannot be part of the container at once so
* add each one in there individually */
- if (task.mChildrenToReparent.size() > 0)
+ if (task.mpChildrenToReparent)
{
- for (MediaList::const_iterator it = task.mChildrenToReparent.begin();
- it != task.mChildrenToReparent.end();
+ MediumLockList::Base::iterator childrenBegin = task.mpChildrenToReparent->GetBegin();
+ MediumLockList::Base::iterator childrenEnd = task.mpChildrenToReparent->GetEnd();
+ for (MediumLockList::Base::iterator it = childrenBegin;
+ it != childrenEnd;
++it)
{
+ Medium *pMedium = it->GetMedium();
/* VD_OPEN_FLAGS_INFO since UUID is wrong yet */
vrc = VDOpen(hdd,
- (*it)->m->strFormat.c_str(),
- (*it)->m->strLocationFull.c_str(),
+ pMedium->m->strFormat.c_str(),
+ pMedium->m->strLocationFull.c_str(),
VD_OPEN_FLAGS_INFO | m->uOpenFlagsDef,
- (*it)->m->vdImageIfaces);
+ pMedium->m->vdImageIfaces);
if (RT_FAILURE(vrc))
throw vrc;
@@ -7011,8 +7237,6 @@ HRESULT Medium::taskMergeHandler(Medium::MergeTask &task)
vrc = VDClose(hdd, false /* fDelete */);
if (RT_FAILURE(vrc))
throw vrc;
-
- (*it)->UnlockWrite(NULL);
}
}
}
@@ -7075,16 +7299,18 @@ HRESULT Medium::taskMergeHandler(Medium::MergeTask &task)
/* reparent source's children and disconnect the deleted
* branch at the younger end */
- if (task.mChildrenToReparent.size() > 0)
+ if (task.mpChildrenToReparent)
{
/* obey {parent,child} lock order */
AutoWriteLock sourceLock(this COMMA_LOCKVAL_SRC_POS);
- for (MediaList::const_iterator it = task.mChildrenToReparent.begin();
- it != task.mChildrenToReparent.end();
- it++)
+ MediumLockList::Base::iterator childrenBegin = task.mpChildrenToReparent->GetBegin();
+ MediumLockList::Base::iterator childrenEnd = task.mpChildrenToReparent->GetEnd();
+ for (MediumLockList::Base::iterator it = childrenBegin;
+ it != childrenEnd;
+ ++it)
{
- Medium *pMedium = *it;
+ Medium *pMedium = it->GetMedium();
AutoWriteLock childLock(pMedium COMMA_LOCKVAL_SRC_POS);
pMedium->deparent(); // removes pMedium from source
@@ -7170,10 +7396,7 @@ HRESULT Medium::taskMergeHandler(Medium::MergeTask &task)
* in the mergeTo() docs. The latter also implies that we
* don't own the merge chain, so release it in this case. */
if (task.isAsync())
- {
- Assert(task.mChildrenToReparent.size() == 0);
- cancelMergeTo(task.mChildrenToReparent, task.mpMediumLockList);
- }
+ cancelMergeTo(task.mpChildrenToReparent, task.mpMediumLockList);
}
return mrc;
@@ -7213,7 +7436,8 @@ HRESULT Medium::taskCloneHandler(Medium::CloneTask &task)
/* The object may request a specific UUID (through a special form of
* the setLocation() argument). Otherwise we have to generate it */
Guid targetId = pTarget->m->id;
- fGenerateUuid = targetId.isEmpty();
+
+ fGenerateUuid = targetId.isZero();
if (fGenerateUuid)
{
targetId.create();
@@ -7258,7 +7482,7 @@ HRESULT Medium::taskCloneHandler(Medium::CloneTask &task)
Utf8Str targetFormat(pTarget->m->strFormat);
Utf8Str targetLocation(pTarget->m->strLocationFull);
- uint64_t capabilities = pTarget->m->formatObj->getCapabilities();
+ uint64_t capabilities = pTarget->m->formatObj->i_getCapabilities();
Assert( pTarget->m->state == MediumState_Creating
|| pTarget->m->state == MediumState_LockedWrite);
@@ -7407,7 +7631,8 @@ HRESULT Medium::taskCloneHandler(Medium::CloneTask &task)
ComObjPtr<Medium> pMedium;
mrc = pParent->m->pVirtualBox->registerMedium(pTarget, &pMedium,
DeviceType_HardDisk);
- Assert(pTarget == pMedium);
+ Assert( FAILED(mrc)
+ || pTarget == pMedium);
eik.fetch();
if (FAILED(mrc))
@@ -7421,7 +7646,8 @@ HRESULT Medium::taskCloneHandler(Medium::CloneTask &task)
ComObjPtr<Medium> pMedium;
mrc = m->pVirtualBox->registerMedium(pTarget, &pMedium,
DeviceType_HardDisk);
- Assert(pTarget == pMedium);
+ Assert( FAILED(mrc)
+ || pTarget == pMedium);
eik.fetch();
}
}
@@ -7672,15 +7898,8 @@ HRESULT Medium::taskResetHandler(Medium::ResetTask &task)
m->logicalSize = logicalSize;
m->variant = variant;
- if (task.isAsync())
- {
- /* unlock ourselves when done */
- HRESULT rc2 = UnlockWrite(NULL);
- AssertComRC(rc2);
- }
-
- /* Note that in sync mode, it's the caller's responsibility to
- * unlock the medium. */
+ /* Everything is explicitly unlocked when the task exits,
+ * as the task destruction also destroys the media chain. */
return rc;
}
@@ -7736,7 +7955,7 @@ HRESULT Medium::taskCompactHandler(Medium::CompactTask &task)
vrc = VDOpen(hdd,
pMedium->m->strFormat.c_str(),
pMedium->m->strLocationFull.c_str(),
- m->uOpenFlagsDef | (it == mediumListLast) ? VD_OPEN_FLAGS_NORMAL : VD_OPEN_FLAGS_READONLY,
+ m->uOpenFlagsDef | (it == mediumListLast ? VD_OPEN_FLAGS_NORMAL : VD_OPEN_FLAGS_READONLY),
pMedium->m->vdImageIfaces);
if (RT_FAILURE(vrc))
throw setError(VBOX_E_FILE_ERROR,
@@ -7792,13 +8011,14 @@ HRESULT Medium::taskResizeHandler(Medium::ResizeTask &task)
{
HRESULT rc = S_OK;
- /* Lock all in {parent,child} order. The lock is also used as a
- * signal from the task initiator (which releases it only after
- * RTThreadCreate()) that we can start the job. */
- AutoWriteLock thisLock(this COMMA_LOCKVAL_SRC_POS);
+ uint64_t size = 0, logicalSize = 0;
try
{
+ /* The lock is also used as a signal from the task initiator (which
+ * releases it only after RTThreadCreate()) that we can start the job */
+ AutoWriteLock thisLock(this COMMA_LOCKVAL_SRC_POS);
+
PVBOXHDD hdd;
int vrc = VDCreate(m->vdDiskIfaces, convertDeviceType(), &hdd);
ComAssertRCThrow(vrc, E_FAIL);
@@ -7833,7 +8053,7 @@ HRESULT Medium::taskResizeHandler(Medium::ResizeTask &task)
vrc = VDOpen(hdd,
pMedium->m->strFormat.c_str(),
pMedium->m->strLocationFull.c_str(),
- m->uOpenFlagsDef | (it == mediumListLast) ? VD_OPEN_FLAGS_NORMAL : VD_OPEN_FLAGS_READONLY,
+ m->uOpenFlagsDef | (it == mediumListLast ? VD_OPEN_FLAGS_NORMAL : VD_OPEN_FLAGS_READONLY),
pMedium->m->vdImageIfaces);
if (RT_FAILURE(vrc))
throw setError(VBOX_E_FILE_ERROR,
@@ -7867,6 +8087,8 @@ HRESULT Medium::taskResizeHandler(Medium::ResizeTask &task)
location.c_str(),
vdError(vrc).c_str());
}
+ size = VDGetFileSize(hdd, VD_LAST_IMAGE);
+ logicalSize = VDGetSize(hdd, VD_LAST_IMAGE);
}
catch (HRESULT aRC) { rc = aRC; }
@@ -7874,6 +8096,13 @@ HRESULT Medium::taskResizeHandler(Medium::ResizeTask &task)
}
catch (HRESULT aRC) { rc = aRC; }
+ if (SUCCEEDED(rc))
+ {
+ AutoWriteLock thisLock(this COMMA_LOCKVAL_SRC_POS);
+ m->size = size;
+ m->logicalSize = logicalSize;
+ }
+
/* Everything is explicitly unlocked when the task exits,
* as the task destruction also destroys the media chain. */
@@ -7936,9 +8165,9 @@ HRESULT Medium::taskExportHandler(Medium::ExportTask &task)
vdError(vrc).c_str());
}
- Utf8Str targetFormat(task.mFormat->getId());
+ Utf8Str targetFormat(task.mFormat->i_getId());
Utf8Str targetLocation(task.mFilename);
- uint64_t capabilities = task.mFormat->getCapabilities();
+ uint64_t capabilities = task.mFormat->i_getCapabilities();
Assert(m->state == MediumState_LockedRead);
@@ -8031,7 +8260,8 @@ HRESULT Medium::taskImportHandler(Medium::ImportTask &task)
/* The object may request a specific UUID (through a special form of
* the setLocation() argument). Otherwise we have to generate it */
Guid targetId = m->id;
- fGenerateUuid = targetId.isEmpty();
+
+ fGenerateUuid = targetId.isZero();
if (fGenerateUuid)
{
targetId.create();
@@ -8048,7 +8278,7 @@ HRESULT Medium::taskImportHandler(Medium::ImportTask &task)
{
/* Open source medium. */
vrc = VDOpen(hdd,
- task.mFormat->getId().c_str(),
+ task.mFormat->i_getId().c_str(),
task.mFilename.c_str(),
VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_SEQUENTIAL | m->uOpenFlagsDef,
task.mVDImageIfaces);
@@ -8060,7 +8290,7 @@ HRESULT Medium::taskImportHandler(Medium::ImportTask &task)
Utf8Str targetFormat(m->strFormat);
Utf8Str targetLocation(m->strLocationFull);
- uint64_t capabilities = task.mFormat->getCapabilities();
+ uint64_t capabilities = task.mFormat->i_getCapabilities();
Assert( m->state == MediumState_Creating
|| m->state == MediumState_LockedWrite);
diff --git a/src/VBox/Main/src-server/MediumLock.cpp b/src/VBox/Main/src-server/MediumLock.cpp
index b8b601ca..567973d4 100644
--- a/src/VBox/Main/src-server/MediumLock.cpp
+++ b/src/VBox/Main/src-server/MediumLock.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -74,7 +74,12 @@ bool MediumLock::GetLockRequest() const
return mLockWrite;
}
-HRESULT MediumLock::Lock()
+bool MediumLock::IsLocked() const
+{
+ return mIsLocked;
+}
+
+HRESULT MediumLock::Lock(bool aIgnoreLockedMedia)
{
if (mIsLocked)
return S_OK;
@@ -101,9 +106,20 @@ HRESULT MediumLock::Lock()
break;
default:
if (mLockWrite)
- rc = mMedium->LockWrite(NULL);
+ {
+ if (aIgnoreLockedMedia && ( state == MediumState_LockedRead
+ || state == MediumState_LockedWrite))
+ return S_OK;
+ else
+ rc = mMedium->LockWrite(mToken.asOutParam());
+ }
else
- rc = mMedium->LockRead(NULL);
+ {
+ if (aIgnoreLockedMedia && state == MediumState_LockedWrite)
+ return S_OK;
+ else
+ rc = mMedium->LockRead(mToken.asOutParam());
+ }
}
if (SUCCEEDED(rc))
{
@@ -120,12 +136,10 @@ HRESULT MediumLock::Lock()
HRESULT MediumLock::Unlock()
{
HRESULT rc = S_OK;
- if (mIsLocked && !mLockSkipped)
+ if (mIsLocked && !mLockSkipped && mToken)
{
- if (mLockWrite)
- rc = mMedium->UnlockWrite(NULL);
- else
- rc = mMedium->UnlockRead(NULL);
+ mToken->Abandon();
+ mToken.setNull();
}
mMediumCaller.attach(NULL);
mLockSkipped = false;
@@ -201,7 +215,7 @@ MediumLockList::Base::iterator MediumLockList::GetEnd()
return mMediumLocks.end();
}
-HRESULT MediumLockList::Lock()
+HRESULT MediumLockList::Lock(bool fSkipOverLockedMedia /* = false */)
{
if (mIsLocked)
return S_OK;
@@ -210,7 +224,7 @@ HRESULT MediumLockList::Lock()
it != mMediumLocks.end();
it++)
{
- rc = it->Lock();
+ rc = it->Lock(fSkipOverLockedMedia);
if (FAILED(rc))
{
for (MediumLockList::Base::iterator it2 = mMediumLocks.begin();
@@ -288,7 +302,9 @@ HRESULT MediumLockListMap::Remove(const ComObjPtr<MediumAttachment> &aMediumAtta
MediumLockListMap::Base::iterator it = mMediumLocks.find(aMediumAttachment);
if (it == mMediumLocks.end())
return VBOX_E_INVALID_OBJECT_STATE;
+ MediumLockList *pMediumLockList = it->second;
mMediumLocks.erase(it);
+ delete pMediumLockList;
return S_OK;
}
diff --git a/src/VBox/Main/src-server/NATEngineImpl.cpp b/src/VBox/Main/src-server/NATEngineImpl.cpp
index 7ce08fd8..e58e533a 100644
--- a/src/VBox/Main/src-server/NATEngineImpl.cpp
+++ b/src/VBox/Main/src-server/NATEngineImpl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010-2012 Oracle Corporation
+ * Copyright (C) 2010-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -26,6 +26,7 @@
#include <VBox/err.h>
#include <VBox/settings.h>
+#include <VBox/com/array.h>
// constructor / destructor
@@ -338,6 +339,7 @@ NATEngine::RemoveRedirect(IN_BSTR aName)
mNATRules.erase(it);
mParent->setModified(Machine::IsModified_NetworkAdapters);
m_fModified = true;
+ mData.commit();
alock.release();
mParent->onNATRedirectRuleChange(ulSlot, TRUE, aName, proto, Bstr(strHostIP).raw(), u16HostPort, Bstr(strGuestIP).raw(), u16GuestPort);
return S_OK;
diff --git a/src/VBox/Main/src-server/NATNetworkImpl.cpp b/src/VBox/Main/src-server/NATNetworkImpl.cpp
new file mode 100644
index 00000000..65327250
--- /dev/null
+++ b/src/VBox/Main/src-server/NATNetworkImpl.cpp
@@ -0,0 +1,1115 @@
+/* $Id: NATNetworkImpl.cpp $ */
+/** @file
+ * INATNetwork implementation.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include <string>
+#include "NetworkServiceRunner.h"
+#include "DHCPServerImpl.h"
+#include "NATNetworkImpl.h"
+#include "AutoCaller.h"
+#include "Logging.h"
+
+#include <iprt/asm.h>
+#include <iprt/cpp/utils.h>
+#include <iprt/cidr.h>
+#include <iprt/net.h>
+#include <VBox/com/array.h>
+#include <VBox/com/ptr.h>
+#include <VBox/settings.h>
+
+#include "EventImpl.h"
+#include "VBoxEvents.h"
+
+#include "VirtualBoxImpl.h"
+#include <algorithm>
+#include <list>
+
+#ifndef RT_OS_WINDOWS
+# include <netinet/in.h>
+#else
+# define IN_LOOPBACKNET 127
+#endif
+
+
+// constructor / destructor
+/////////////////////////////////////////////////////////////////////////////
+
+struct NATNetwork::Data
+{
+ Data()
+ : fEnabled(TRUE)
+ , fIPv6Enabled(FALSE)
+ , fAdvertiseDefaultIPv6Route(FALSE)
+ , fNeedDhcpServer(TRUE)
+ , u32LoopbackIp6(0)
+ , offGateway(0)
+ , offDhcp(0)
+ {
+ IPv4Gateway.setNull();
+ IPv4NetworkCidr.setNull();
+ IPv6Prefix.setNull();
+ IPv4DhcpServer.setNull();
+ IPv4NetworkMask.setNull();
+ IPv4DhcpServerLowerIp.setNull();
+ IPv4DhcpServerUpperIp.setNull();
+ }
+ virtual ~Data(){}
+ const ComObjPtr<EventSource> pEventSource;
+#ifdef VBOX_WITH_NAT_SERVICE
+ NATNetworkServiceRunner NATRunner;
+ ComObjPtr<IDHCPServer> dhcpServer;
+#endif
+ Bstr IPv4Gateway;
+ Bstr IPv4NetworkCidr;
+ Bstr IPv4NetworkMask;
+ Bstr IPv4DhcpServer;
+ Bstr IPv4DhcpServerLowerIp;
+ Bstr IPv4DhcpServerUpperIp;
+ BOOL fEnabled;
+ BOOL fIPv6Enabled;
+ Bstr IPv6Prefix;
+ BOOL fAdvertiseDefaultIPv6Route;
+ BOOL fNeedDhcpServer;
+ NATRuleMap mapName2PortForwardRule4;
+ NATRuleMap mapName2PortForwardRule6;
+ settings::NATLoopbackOffsetList llNATLoopbackOffsetList;
+ uint32_t u32LoopbackIp6;
+ uint32_t offGateway;
+ uint32_t offDhcp;
+};
+
+
+NATNetwork::NATNetwork()
+ : mVirtualBox(NULL)
+{
+}
+
+
+NATNetwork::~NATNetwork()
+{
+}
+
+
+HRESULT NATNetwork::FinalConstruct()
+{
+ return BaseFinalConstruct();
+}
+
+
+void NATNetwork::FinalRelease()
+{
+ uninit ();
+
+ BaseFinalRelease();
+}
+
+
+void NATNetwork::uninit()
+{
+ /* Enclose the state transition Ready->InUninit->NotReady */
+ AutoUninitSpan autoUninitSpan(this);
+ if (autoUninitSpan.uninitDone())
+ return;
+ delete m;
+ m = NULL;
+ unconst(mVirtualBox) = NULL;
+}
+
+
+HRESULT NATNetwork::init(VirtualBox *aVirtualBox, IN_BSTR aName)
+{
+ AssertReturn(aName != NULL, E_INVALIDARG);
+
+ AutoInitSpan autoInitSpan(this);
+ AssertReturn(autoInitSpan.isOk(), E_FAIL);
+
+ /* share VirtualBox weakly (parent remains NULL so far) */
+ unconst(mVirtualBox) = aVirtualBox;
+ unconst(mName) = aName;
+ m = new Data();
+ m->offGateway = 1;
+ m->IPv4NetworkCidr = "10.0.2.0/24";
+ m->IPv6Prefix = "fe80::/64";
+
+ settings::NATHostLoopbackOffset off;
+ off.strLoopbackHostAddress = "127.0.0.1";
+ off.u32Offset = (uint32_t)2;
+ m->llNATLoopbackOffsetList.push_back(off);
+
+ recalculateIpv4AddressAssignments();
+
+ HRESULT hrc = unconst(m->pEventSource).createObject();
+ if (FAILED(hrc)) throw hrc;
+
+ hrc = m->pEventSource->init();
+ if (FAILED(hrc)) throw hrc;
+
+ /* Confirm a successful initialization */
+ autoInitSpan.setSucceeded();
+
+ return S_OK;
+}
+
+
+HRESULT NATNetwork::init(VirtualBox *aVirtualBox,
+ const settings::NATNetwork &data)
+{
+ /* Enclose the state transition NotReady->InInit->Ready */
+ AutoInitSpan autoInitSpan(this);
+ AssertReturn(autoInitSpan.isOk(), E_FAIL);
+
+ /* share VirtualBox weakly (parent remains NULL so far) */
+ unconst(mVirtualBox) = aVirtualBox;
+
+ unconst(mName) = data.strNetworkName;
+ m = new Data();
+ m->IPv4NetworkCidr = data.strNetwork;
+ m->fEnabled = data.fEnabled;
+ m->fAdvertiseDefaultIPv6Route = data.fAdvertiseDefaultIPv6Route;
+ m->fNeedDhcpServer = data.fNeedDhcpServer;
+ m->fIPv6Enabled = data.fIPv6;
+
+ m->u32LoopbackIp6 = data.u32HostLoopback6Offset;
+
+ m->llNATLoopbackOffsetList.clear();
+ m->llNATLoopbackOffsetList.assign(data.llHostLoopbackOffsetList.begin(),
+ data.llHostLoopbackOffsetList.end());
+
+ recalculateIpv4AddressAssignments();
+
+ /* IPv4 port-forward rules */
+ m->mapName2PortForwardRule4.clear();
+ for (settings::NATRuleList::const_iterator it = data.llPortForwardRules4.begin();
+ it != data.llPortForwardRules4.end(); ++it)
+ {
+ m->mapName2PortForwardRule4.insert(std::make_pair(it->strName.c_str(), *it));
+ }
+
+ /* IPv6 port-forward rules */
+ m->mapName2PortForwardRule6.clear();
+ for (settings::NATRuleList::const_iterator it = data.llPortForwardRules6.begin();
+ it != data.llPortForwardRules6.end(); ++it)
+ {
+ m->mapName2PortForwardRule6.insert(std::make_pair(it->strName, *it));
+ }
+
+ HRESULT hrc = unconst(m->pEventSource).createObject();
+ if (FAILED(hrc)) throw hrc;
+
+ hrc = m->pEventSource->init();
+ if (FAILED(hrc)) throw hrc;
+
+ autoInitSpan.setSucceeded();
+
+ return S_OK;
+}
+
+
+HRESULT NATNetwork::saveSettings(settings::NATNetwork &data)
+{
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ data.strNetworkName = mName;
+ data.strNetwork = m->IPv4NetworkCidr;
+ data.fEnabled = RT_BOOL(m->fEnabled);
+ data.fAdvertiseDefaultIPv6Route = RT_BOOL(m->fAdvertiseDefaultIPv6Route);
+ data.fNeedDhcpServer = RT_BOOL(m->fNeedDhcpServer);
+ data.fIPv6 = RT_BOOL(m->fIPv6Enabled);
+ data.strIPv6Prefix = m->IPv6Prefix;
+
+ /* saving ipv4 port-forward Rules*/
+ data.llPortForwardRules4.clear();
+ for (NATRuleMap::iterator it = m->mapName2PortForwardRule4.begin();
+ it != m->mapName2PortForwardRule4.end(); ++it)
+ data.llPortForwardRules4.push_back(it->second);
+
+ /* saving ipv6 port-forward Rules*/
+ data.llPortForwardRules6.clear();
+ for (NATRuleMap::iterator it = m->mapName2PortForwardRule6.begin();
+ it != m->mapName2PortForwardRule6.end(); ++it)
+ data.llPortForwardRules6.push_back(it->second);
+
+ data.u32HostLoopback6Offset = m->u32LoopbackIp6;
+
+ data.llHostLoopbackOffsetList.clear();
+ data.llHostLoopbackOffsetList.assign(m->llNATLoopbackOffsetList.begin(),
+ m->llNATLoopbackOffsetList.end());
+
+ mVirtualBox->onNATNetworkSetting(mName.raw(),
+ data.fEnabled ? TRUE : FALSE,
+ m->IPv4NetworkCidr.raw(),
+ m->IPv4Gateway.raw(),
+ data.fAdvertiseDefaultIPv6Route ? TRUE : FALSE,
+ data.fNeedDhcpServer ? TRUE : FALSE);
+
+ /* Notify listerners listening on this network only */
+ fireNATNetworkSettingEvent(m->pEventSource,
+ mName.raw(),
+ data.fEnabled ? TRUE : FALSE,
+ m->IPv4NetworkCidr.raw(),
+ m->IPv4Gateway.raw(),
+ data.fAdvertiseDefaultIPv6Route ? TRUE : FALSE,
+ data.fNeedDhcpServer ? TRUE : FALSE);
+
+ return S_OK;
+}
+
+
+STDMETHODIMP NATNetwork::COMGETTER(EventSource)(IEventSource ** aEventSource)
+{
+ CheckComArgOutPointerValid(aEventSource);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ /* event source is const, no need to lock */
+ m->pEventSource.queryInterfaceTo(aEventSource);
+
+ return S_OK;
+}
+
+
+STDMETHODIMP NATNetwork::COMGETTER(NetworkName)(BSTR *aName)
+{
+ CheckComArgOutPointerValid(aName);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ mName.cloneTo(aName);
+
+ return S_OK;
+}
+
+
+STDMETHODIMP NATNetwork::COMSETTER(NetworkName)(IN_BSTR aName)
+{
+ CheckComArgOutPointerValid(aName);
+ AutoCaller autoCaller(this);
+
+ if (FAILED(autoCaller.rc()))
+ return autoCaller.rc();
+
+ {
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (aName == mName)
+ return S_OK;
+
+ unconst(mName) = aName;
+ }
+
+ AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
+ HRESULT rc = mVirtualBox->saveSettings();
+ ComAssertComRCRetRC(rc);
+
+ return S_OK;
+}
+
+
+STDMETHODIMP NATNetwork::COMGETTER(Enabled)(BOOL *aEnabled)
+{
+ CheckComArgOutPointerValid(aEnabled);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ *aEnabled = m->fEnabled;
+ recalculateIpv4AddressAssignments();
+
+ return S_OK;
+}
+
+
+STDMETHODIMP NATNetwork::COMSETTER(Enabled)(BOOL aEnabled)
+{
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc()))
+ return autoCaller.rc();
+
+ {
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (aEnabled == m->fEnabled)
+ return S_OK;
+
+ m->fEnabled = aEnabled;
+ }
+
+ AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
+ HRESULT rc = mVirtualBox->saveSettings();
+ ComAssertComRCRetRC(rc);
+
+ return S_OK;
+}
+
+
+STDMETHODIMP NATNetwork::COMGETTER(Gateway)(BSTR *aIPv4Gateway)
+{
+ CheckComArgOutPointerValid(aIPv4Gateway);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ m->IPv4Gateway.cloneTo(aIPv4Gateway);
+
+ return S_OK;
+}
+
+
+STDMETHODIMP NATNetwork::COMGETTER(Network)(BSTR *aIPv4NetworkCidr)
+{
+ CheckComArgOutPointerValid(aIPv4NetworkCidr);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+ m->IPv4NetworkCidr.cloneTo(aIPv4NetworkCidr);
+ return S_OK;
+}
+
+
+STDMETHODIMP NATNetwork::COMSETTER(Network)(IN_BSTR aIPv4NetworkCidr)
+{
+ CheckComArgOutPointerValid(aIPv4NetworkCidr);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc()))
+ return autoCaller.rc();
+
+ {
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (aIPv4NetworkCidr == m->IPv4NetworkCidr)
+ return S_OK;
+
+ /* silently ignore network cidr update for now.
+ * todo: keep internally guest address of port forward rule
+ * as offset from network id.
+ */
+ if (!m->mapName2PortForwardRule4.empty())
+ return S_OK;
+
+ unconst(m->IPv4NetworkCidr) = Bstr(aIPv4NetworkCidr);
+ recalculateIpv4AddressAssignments();
+ }
+
+ AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
+ HRESULT rc = mVirtualBox->saveSettings();
+ ComAssertComRCRetRC(rc);
+
+ return S_OK;
+}
+
+
+STDMETHODIMP NATNetwork::COMGETTER(IPv6Enabled)(BOOL *aIPv6Enabled)
+{
+ CheckComArgOutPointerValid(aIPv6Enabled);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ *aIPv6Enabled = m->fIPv6Enabled;
+
+ return S_OK;
+}
+
+
+STDMETHODIMP NATNetwork::COMSETTER(IPv6Enabled)(BOOL aIPv6Enabled)
+{
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc()))
+ return autoCaller.rc();
+
+ {
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (aIPv6Enabled == m->fIPv6Enabled)
+ return S_OK;
+
+ m->fIPv6Enabled = aIPv6Enabled;
+ }
+
+ AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
+ HRESULT rc = mVirtualBox->saveSettings();
+ ComAssertComRCRetRC(rc);
+
+ return S_OK;
+}
+
+
+STDMETHODIMP NATNetwork::COMGETTER(IPv6Prefix) (BSTR *aIPv6Prefix)
+{
+ CheckComArgOutPointerValid(aIPv6Prefix);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ m->IPv6Prefix.cloneTo(aIPv6Prefix);
+
+ return S_OK;
+}
+
+
+STDMETHODIMP NATNetwork::COMSETTER(IPv6Prefix) (IN_BSTR aIPv6Prefix)
+{
+ CheckComArgOutPointerValid(aIPv6Prefix);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc()))
+ return autoCaller.rc();
+
+ {
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (aIPv6Prefix == m->IPv6Prefix)
+ return S_OK;
+
+ /* silently ignore network IPv6 prefix update.
+ * todo: see similar todo in NATNetwork::COMSETTER(Network)(IN_BSTR)
+ */
+ if (!m->mapName2PortForwardRule6.empty())
+ return S_OK;
+
+ unconst(m->IPv6Prefix) = Bstr(aIPv6Prefix);
+ }
+
+ AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
+ HRESULT rc = mVirtualBox->saveSettings();
+ ComAssertComRCRetRC(rc);
+
+ return S_OK;
+}
+
+
+STDMETHODIMP NATNetwork::COMGETTER(AdvertiseDefaultIPv6RouteEnabled)(BOOL *aAdvertiseDefaultIPv6Route)
+{
+ CheckComArgOutPointerValid(aAdvertiseDefaultIPv6Route);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ *aAdvertiseDefaultIPv6Route = m->fAdvertiseDefaultIPv6Route;
+
+ return S_OK;
+}
+
+
+STDMETHODIMP NATNetwork::COMSETTER(AdvertiseDefaultIPv6RouteEnabled)(BOOL aAdvertiseDefaultIPv6Route)
+{
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc()))
+ return autoCaller.rc();
+
+ {
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (aAdvertiseDefaultIPv6Route == m->fAdvertiseDefaultIPv6Route)
+ return S_OK;
+
+ m->fAdvertiseDefaultIPv6Route = aAdvertiseDefaultIPv6Route;
+
+ }
+
+ AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
+ HRESULT rc = mVirtualBox->saveSettings();
+ ComAssertComRCRetRC(rc);
+
+ return S_OK;
+}
+
+
+STDMETHODIMP NATNetwork::COMGETTER(NeedDhcpServer)(BOOL *aNeedDhcpServer)
+{
+ CheckComArgOutPointerValid(aNeedDhcpServer);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ *aNeedDhcpServer = m->fNeedDhcpServer;
+
+ return S_OK;
+}
+
+
+STDMETHODIMP NATNetwork::COMSETTER(NeedDhcpServer)(BOOL aNeedDhcpServer)
+{
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc()))
+ return autoCaller.rc();
+
+ {
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (aNeedDhcpServer == m->fNeedDhcpServer)
+ return S_OK;
+
+ m->fNeedDhcpServer = aNeedDhcpServer;
+
+ recalculateIpv4AddressAssignments();
+
+ }
+
+ AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
+ HRESULT rc = mVirtualBox->saveSettings();
+ ComAssertComRCRetRC(rc);
+
+ return S_OK;
+}
+
+
+STDMETHODIMP NATNetwork::COMGETTER(LocalMappings)(ComSafeArrayOut(BSTR, aLocalMappings))
+{
+ CheckComArgOutSafeArrayPointerValid(aLocalMappings);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ com::SafeArray<BSTR> sf(m->llNATLoopbackOffsetList.size());
+
+ size_t i = 0;
+ settings::NATLoopbackOffsetList::const_iterator it;
+
+ for (it = m->llNATLoopbackOffsetList.begin();
+ it != m->llNATLoopbackOffsetList.end(); ++it, ++i)
+ {
+ BstrFmt bstr("%s=%d",
+ (*it).strLoopbackHostAddress.c_str(),
+ (*it).u32Offset);
+ bstr.detachTo(&sf[i]);
+ }
+ sf.detachTo(ComSafeArrayOutArg(aLocalMappings));
+
+ return S_OK;
+}
+
+
+STDMETHODIMP NATNetwork::AddLocalMapping(IN_BSTR aHostId, LONG aOffset)
+{
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ //AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ RTNETADDRIPV4 addr, net, mask;
+
+ int rc = RTNetStrToIPv4Addr(Utf8Str(aHostId).c_str(), &addr);
+ if (RT_FAILURE(rc))
+ return E_INVALIDARG;
+
+ /* check against 127/8 */
+ if ((RT_N2H_U32(addr.u) >> IN_CLASSA_NSHIFT) != IN_LOOPBACKNET)
+ return E_INVALIDARG;
+
+ /* check against networkid vs network mask */
+ rc = RTCidrStrToIPv4(Utf8Str(m->IPv4NetworkCidr).c_str(), &net, &mask);
+ if (RT_FAILURE(rc))
+ return E_INVALIDARG;
+
+ if (((net.u + aOffset) & mask.u) != net.u)
+ return E_INVALIDARG;
+
+ settings::NATLoopbackOffsetList::iterator it;
+
+ it = std::find(m->llNATLoopbackOffsetList.begin(),
+ m->llNATLoopbackOffsetList.end(),
+ Utf8Str(aHostId).c_str());
+
+ if (it != m->llNATLoopbackOffsetList.end())
+ {
+ if (aOffset == 0) /* erase */
+ m->llNATLoopbackOffsetList.erase(it, it);
+ else /* modify */
+ {
+ settings::NATLoopbackOffsetList::iterator it1;
+ it1 = std::find(m->llNATLoopbackOffsetList.begin(),
+ m->llNATLoopbackOffsetList.end(),
+ (uint32_t)aOffset);
+ if (it1 != m->llNATLoopbackOffsetList.end())
+ return E_INVALIDARG; /* this offset is already registered. */
+
+ (*it).u32Offset = aOffset;
+ }
+
+ AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
+ return mVirtualBox->saveSettings();
+ }
+
+ /* injection */
+ it = std::find(m->llNATLoopbackOffsetList.begin(),
+ m->llNATLoopbackOffsetList.end(),
+ (uint32_t)aOffset);
+
+ if (it != m->llNATLoopbackOffsetList.end())
+ return E_INVALIDARG; /* offset is already registered. */
+
+ settings::NATHostLoopbackOffset off;
+ off.strLoopbackHostAddress = aHostId;
+ off.u32Offset = (uint32_t)aOffset;
+ m->llNATLoopbackOffsetList.push_back(off);
+
+ AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
+ return mVirtualBox->saveSettings();
+}
+
+
+STDMETHODIMP NATNetwork::COMGETTER(LoopbackIp6)(LONG *aLoopbackIp6)
+{
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ *aLoopbackIp6 = m->u32LoopbackIp6;
+ return S_OK;
+}
+
+
+STDMETHODIMP NATNetwork::COMSETTER(LoopbackIp6)(LONG aLoopbackIp6)
+{
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc()))
+ return autoCaller.rc();
+
+ {
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (aLoopbackIp6 < 0)
+ return E_INVALIDARG;
+
+ if (static_cast<uint32_t>(aLoopbackIp6) == m->u32LoopbackIp6)
+ return S_OK;
+
+ m->u32LoopbackIp6 = aLoopbackIp6;
+ }
+
+ AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
+ return mVirtualBox->saveSettings();
+}
+
+
+STDMETHODIMP NATNetwork::COMGETTER(PortForwardRules4)(ComSafeArrayOut(BSTR, aPortForwardRules4))
+{
+ CheckComArgOutSafeArrayPointerValid(aPortForwardRules4);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+ GetPortForwardRulesFromMap(ComSafeArrayInArg(aPortForwardRules4),
+ m->mapName2PortForwardRule4);
+ return S_OK;
+}
+
+STDMETHODIMP NATNetwork::COMGETTER(PortForwardRules6)(ComSafeArrayOut(BSTR,
+ aPortForwardRules6))
+{
+ CheckComArgOutSafeArrayPointerValid(aPortForwardRules6);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+ GetPortForwardRulesFromMap(ComSafeArrayInArg(aPortForwardRules6), m->mapName2PortForwardRule6);
+ return S_OK;
+}
+
+
+STDMETHODIMP NATNetwork::AddPortForwardRule(BOOL aIsIpv6,
+ IN_BSTR aPortForwardRuleName,
+ NATProtocol_T aProto,
+ IN_BSTR aHostIp,
+ USHORT aHostPort,
+ IN_BSTR aGuestIp,
+ USHORT aGuestPort)
+{
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc()))
+ return autoCaller.rc();
+
+ {
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+ Utf8Str name = aPortForwardRuleName;
+ Utf8Str proto;
+ settings::NATRule r;
+ NATRuleMap& mapRules = aIsIpv6 ? m->mapName2PortForwardRule6 : m->mapName2PortForwardRule4;
+ switch (aProto)
+ {
+ case NATProtocol_TCP:
+ proto = "tcp";
+ break;
+ case NATProtocol_UDP:
+ proto = "udp";
+ break;
+ default:
+ return E_INVALIDARG;
+ }
+ if (name.isEmpty())
+ name = Utf8StrFmt("%s_[%s]%%%d_[%s]%%%d", proto.c_str(),
+ Utf8Str(aHostIp).c_str(), aHostPort,
+ Utf8Str(aGuestIp).c_str(), aGuestPort);
+
+ NATRuleMap::iterator it;
+
+ for (it = mapRules.begin(); it != mapRules.end(); ++it)
+ {
+ r = it->second;
+ if (it->first == name)
+ return setError(E_INVALIDARG,
+ tr("A NAT rule of this name already exists"));
+ if ( r.strHostIP == Utf8Str(aHostIp)
+ && r.u16HostPort == aHostPort
+ && r.proto == aProto)
+ return setError(E_INVALIDARG,
+ tr("A NAT rule for this host port and this host IP already exists"));
+ }
+
+ r.strName = name.c_str();
+ r.proto = aProto;
+ r.strHostIP = aHostIp;
+ r.u16HostPort = aHostPort;
+ r.strGuestIP = aGuestIp;
+ r.u16GuestPort = aGuestPort;
+ mapRules.insert(std::make_pair(name, r));
+ }
+
+ {
+ AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
+ HRESULT rc = mVirtualBox->saveSettings();
+ ComAssertComRCRetRC(rc);
+ }
+
+ mVirtualBox->onNATNetworkPortForward(mName.raw(), TRUE, aIsIpv6,
+ aPortForwardRuleName, aProto,
+ aHostIp, aHostPort,
+ aGuestIp, aGuestPort);
+
+ /* Notify listerners listening on this network only */
+ fireNATNetworkPortForwardEvent(m->pEventSource, mName.raw(), TRUE,
+ aIsIpv6, aPortForwardRuleName, aProto,
+ aHostIp, aHostPort,
+ aGuestIp, aGuestPort);
+ return S_OK;
+}
+
+
+STDMETHODIMP NATNetwork::RemovePortForwardRule(BOOL aIsIpv6, IN_BSTR aPortForwardRuleName)
+{
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc()))
+ return autoCaller.rc();
+
+ Utf8Str strHostIP;
+ Utf8Str strGuestIP;
+ uint16_t u16HostPort;
+ uint16_t u16GuestPort;
+ NATProtocol_T proto;
+
+
+ {
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+ NATRuleMap& mapRules = aIsIpv6 ? m->mapName2PortForwardRule6
+ : m->mapName2PortForwardRule4;
+
+ NATRuleMap::iterator it = mapRules.find(aPortForwardRuleName);
+
+ if (it == mapRules.end())
+ return E_INVALIDARG;
+
+ strHostIP = it->second.strHostIP;
+ strGuestIP = it->second.strGuestIP;
+ u16HostPort = it->second.u16HostPort;
+ u16GuestPort = it->second.u16GuestPort;
+ proto = it->second.proto;
+
+ mapRules.erase(it);
+ }
+
+ {
+ AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
+ HRESULT rc = mVirtualBox->saveSettings();
+ ComAssertComRCRetRC(rc);
+ }
+
+ mVirtualBox->onNATNetworkPortForward(mName.raw(), FALSE, aIsIpv6,
+ aPortForwardRuleName, proto,
+ Bstr(strHostIP).raw(), u16HostPort,
+ Bstr(strGuestIP).raw(), u16GuestPort);
+
+ /* Notify listerners listening on this network only */
+ fireNATNetworkPortForwardEvent(m->pEventSource, mName.raw(), FALSE,
+ aIsIpv6, aPortForwardRuleName, proto,
+ Bstr(strHostIP).raw(), u16HostPort,
+ Bstr(strGuestIP).raw(), u16GuestPort);
+ return S_OK;
+}
+
+
+STDMETHODIMP NATNetwork::Start(IN_BSTR aTrunkType)
+{
+#ifdef VBOX_WITH_NAT_SERVICE
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ if (!m->fEnabled) return S_OK;
+
+ m->NATRunner.setOption(NetworkServiceRunner::kNsrKeyNetwork, Utf8Str(mName).c_str());
+ m->NATRunner.setOption(NetworkServiceRunner::kNsrKeyTrunkType, Utf8Str(aTrunkType).c_str());
+ m->NATRunner.setOption(NetworkServiceRunner::kNsrIpAddress, Utf8Str(m->IPv4Gateway).c_str());
+ m->NATRunner.setOption(NetworkServiceRunner::kNsrIpNetmask, Utf8Str(m->IPv4NetworkMask).c_str());
+
+ /* No portforwarding rules from command-line, all will be fetched via API */
+
+ if (m->fNeedDhcpServer)
+ {
+ /*
+ * Just to as idea... via API (on creation user pass the cidr of network and)
+ * and we calculate it's addreses (mutable?).
+ */
+
+ /*
+ * Configuration and running DHCP server:
+ * 1. find server first createDHCPServer
+ * 2. if return status is E_INVALARG => server already exists just find and start.
+ * 3. if return status neither E_INVALRG nor S_OK => return E_FAIL
+ * 4. if return status S_OK proceed to DHCP server configuration
+ * 5. call setConfiguration() and pass all required parameters
+ * 6. start dhcp server.
+ */
+ HRESULT hrc = mVirtualBox->FindDHCPServerByNetworkName(mName.raw(),
+ m->dhcpServer.asOutParam());
+ switch (hrc)
+ {
+ case E_INVALIDARG:
+ /* server haven't beeen found let create it then */
+ hrc = mVirtualBox->CreateDHCPServer(mName.raw(),
+ m->dhcpServer.asOutParam());
+ if (FAILED(hrc))
+ return E_FAIL;
+ /* breakthrough */
+
+ {
+ LogFunc(("gateway: %s, dhcpserver:%s, dhcplowerip:%s, dhcpupperip:%s\n",
+ Utf8Str(m->IPv4Gateway.raw()).c_str(),
+ Utf8Str(m->IPv4DhcpServer.raw()).c_str(),
+ Utf8Str(m->IPv4DhcpServerLowerIp.raw()).c_str(),
+ Utf8Str(m->IPv4DhcpServerUpperIp.raw()).c_str()));
+
+ hrc = m->dhcpServer->COMSETTER(Enabled)(true);
+
+ BSTR dhcpip = NULL;
+ BSTR netmask = NULL;
+ BSTR lowerip = NULL;
+ BSTR upperip = NULL;
+
+ m->IPv4DhcpServer.cloneTo(&dhcpip);
+ m->IPv4NetworkMask.cloneTo(&netmask);
+ m->IPv4DhcpServerLowerIp.cloneTo(&lowerip);
+ m->IPv4DhcpServerUpperIp.cloneTo(&upperip);
+ hrc = m->dhcpServer->SetConfiguration(dhcpip,
+ netmask,
+ lowerip,
+ upperip);
+ }
+ case S_OK:
+ break;
+
+ default:
+ return E_FAIL;
+ }
+
+ /* XXX: AddGlobalOption(DhcpOpt_Router,) - enables attachement of DhcpServer to Main. */
+ m->dhcpServer->AddGlobalOption(DhcpOpt_Router, m->IPv4Gateway.raw());
+
+ hrc = m->dhcpServer->Start(mName.raw(), Bstr("").raw(), aTrunkType);
+ if (FAILED(hrc))
+ {
+ m->dhcpServer.setNull();
+ return E_FAIL;
+ }
+ }
+
+ if (RT_SUCCESS(m->NATRunner.start()))
+ {
+ mVirtualBox->onNATNetworkStartStop(mName.raw(), TRUE);
+ return S_OK;
+ }
+ /** @todo missing setError()! */
+ return E_FAIL;
+#else
+ NOREF(aTrunkType);
+ ReturnComNotImplemented();
+#endif
+}
+
+
+STDMETHODIMP NATNetwork::Stop()
+{
+#ifdef VBOX_WITH_NAT_SERVICE
+ if (!m->dhcpServer.isNull())
+ m->dhcpServer->Stop();
+
+ if (RT_SUCCESS(m->NATRunner.stop()))
+ {
+ mVirtualBox->onNATNetworkStartStop(mName.raw(), FALSE);
+ return S_OK;
+ }
+ /** @todo missing setError()! */
+ return E_FAIL;
+#else
+ ReturnComNotImplemented();
+#endif
+}
+
+
+void NATNetwork::GetPortForwardRulesFromMap(ComSafeArrayOut(BSTR, aPortForwardRules), NATRuleMap& aRules)
+{
+ com::SafeArray<BSTR> sf(aRules.size());
+ size_t i = 0;
+ NATRuleMap::const_iterator it;
+ for (it = aRules.begin();
+ it != aRules.end(); ++it, ++i)
+ {
+ settings::NATRule r = it->second;
+ BstrFmt bstr("%s:%s:[%s]:%d:[%s]:%d",
+ r.strName.c_str(),
+ (r.proto == NATProtocol_TCP? "tcp" : "udp"),
+ r.strHostIP.c_str(),
+ r.u16HostPort,
+ r.strGuestIP.c_str(),
+ r.u16GuestPort);
+ bstr.detachTo(&sf[i]);
+ }
+ sf.detachTo(ComSafeArrayOutArg(aPortForwardRules));
+}
+
+
+int NATNetwork::findFirstAvailableOffset(ADDRESSLOOKUPTYPE addrType, uint32_t *poff)
+{
+ RTNETADDRIPV4 network, netmask;
+
+ int rc = RTCidrStrToIPv4(Utf8Str(m->IPv4NetworkCidr.raw()).c_str(),
+ &network,
+ &netmask);
+ AssertRCReturn(rc, rc);
+
+ uint32_t off;
+ settings::NATLoopbackOffsetList::iterator it;
+ for (off = 1; off < ~netmask.u; ++off)
+ {
+
+ bool skip = false;
+ for (it = m->llNATLoopbackOffsetList.begin();
+ it != m->llNATLoopbackOffsetList.end();
+ ++it)
+ {
+ if ((*it).u32Offset == off)
+ {
+ skip = true;
+ break;
+ }
+
+ }
+
+ if (skip)
+ continue;
+
+ if (off == m->offGateway)
+ {
+ if (addrType == ADDR_GATEWAY)
+ break;
+ else
+ continue;
+ }
+
+ if (off == m->offDhcp)
+ {
+ if (addrType == ADDR_DHCP)
+ break;
+ else
+ continue;
+ }
+
+ if (!skip)
+ break;
+ }
+
+ if (poff)
+ *poff = off;
+
+ return VINF_SUCCESS;
+}
+
+
+int NATNetwork::recalculateIpv4AddressAssignments()
+{
+ RTNETADDRIPV4 network, netmask;
+ int rc = RTCidrStrToIPv4(Utf8Str(m->IPv4NetworkCidr.raw()).c_str(),
+ &network,
+ &netmask);
+ AssertRCReturn(rc, rc);
+
+ findFirstAvailableOffset(ADDR_GATEWAY, &m->offGateway);
+ if (m->fNeedDhcpServer)
+ findFirstAvailableOffset(ADDR_DHCP, &m->offDhcp);
+
+ /* I don't remember the reason CIDR calculated on the host. */
+ RTNETADDRIPV4 gateway = network;
+ gateway.u += m->offGateway;
+ gateway.u = RT_H2N_U32(gateway.u);
+ char szTmpIp[16];
+ RTStrPrintf(szTmpIp, sizeof(szTmpIp), "%RTnaipv4", gateway);
+ m->IPv4Gateway = szTmpIp;
+
+ if (m->fNeedDhcpServer)
+ {
+ RTNETADDRIPV4 dhcpserver = network;
+ dhcpserver.u += m->offDhcp;
+
+ /* XXX: adding more services should change the math here */
+ RTNETADDRIPV4 dhcplowerip = network;
+ uint32_t offDhcpLowerIp;
+ findFirstAvailableOffset(ADDR_DHCPLOWERIP, &offDhcpLowerIp);
+ dhcplowerip.u = RT_H2N_U32(dhcplowerip.u + offDhcpLowerIp);
+
+ RTNETADDRIPV4 dhcpupperip;
+ dhcpupperip.u = RT_H2N_U32((network.u | ~netmask.u) - 1);
+
+ dhcpserver.u = RT_H2N_U32(dhcpserver.u);
+ network.u = RT_H2N_U32(network.u);
+
+ RTStrPrintf(szTmpIp, sizeof(szTmpIp), "%RTnaipv4", dhcpserver);
+ m->IPv4DhcpServer = szTmpIp;
+ RTStrPrintf(szTmpIp, sizeof(szTmpIp), "%RTnaipv4", dhcplowerip);
+ m->IPv4DhcpServerLowerIp = szTmpIp;
+ RTStrPrintf(szTmpIp, sizeof(szTmpIp), "%RTnaipv4", dhcpupperip);
+ m->IPv4DhcpServerUpperIp = szTmpIp;
+
+ LogFunc(("network:%RTnaipv4, dhcpserver:%RTnaipv4, dhcplowerip:%RTnaipv4, dhcpupperip:%RTnaipv4\n",
+ network, dhcpserver, dhcplowerip, dhcpupperip));
+ }
+
+ /* we need IPv4NetworkMask for NAT's gw service start */
+ netmask.u = RT_H2N_U32(netmask.u);
+ RTStrPrintf(szTmpIp, 16, "%RTnaipv4", netmask);
+ m->IPv4NetworkMask = szTmpIp;
+
+ LogFlowFunc(("getaway:%RTnaipv4, netmask:%RTnaipv4\n", gateway, netmask));
+ return VINF_SUCCESS;
+}
diff --git a/src/VBox/Main/src-server/DHCPServerRunner.cpp b/src/VBox/Main/src-server/NATNetworkServiceRunner.cpp
index aab7c8a9..5b51db5b 100644
--- a/src/VBox/Main/src-server/DHCPServerRunner.cpp
+++ b/src/VBox/Main/src-server/NATNetworkServiceRunner.cpp
@@ -1,10 +1,10 @@
-/* $Id: DHCPServerRunner.cpp $ */
+/* $Id: NATNetworkServiceRunner.cpp $ */
/** @file
- * VirtualBox Main - interface for VBox DHCP server
+ * VirtualBox Main - interface for VBox NAT Network service
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -14,43 +14,36 @@
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
-#include "DHCPServerRunner.h"
+#include "NATNetworkServiceRunner.h"
#include <iprt/process.h>
#include <iprt/param.h>
#include <iprt/env.h>
struct ARGDEF
{
- DHCPCFG Type;
+ NATSCCFG Type;
const char * Name;
};
#ifdef RT_OS_WINDOWS
-# define DHCP_EXECUTABLE_NAME "VBoxNetDHCP.exe"
+# define NATSR_EXECUTABLE_NAME "VBoxNetNAT.exe"
#else
-# define DHCP_EXECUTABLE_NAME "VBoxNetDHCP"
+# define NATSR_EXECUTABLE_NAME "VBoxNetNAT"
#endif
static const ARGDEF g_aArgDefs[] =
{
- {DHCPCFG_NAME, "--name"},
- {DHCPCFG_NETNAME, "--network"},
- {DHCPCFG_TRUNKTYPE, "--trunk-type"},
- {DHCPCFG_TRUNKNAME, "--trunk-name"},
- {DHCPCFG_MACADDRESS, "--mac-address"},
- {DHCPCFG_IPADDRESS, "--ip-address"},
- {DHCPCFG_LEASEDB, "--lease-db"},
- {DHCPCFG_VERBOSE, "--verbose"},
- {DHCPCFG_BEGINCONFIG, "--begin-config"},
- {DHCPCFG_GATEWAY, "--gateway"},
- {DHCPCFG_LOWERIP, "--lower-ip"},
- {DHCPCFG_UPPERIP, "--upper-ip"},
- {DHCPCFG_NETMASK, "--netmask"},
- {DHCPCFG_HELP, "--help"},
- {DHCPCFG_VERSION, "--version"}
+ {NATSCCFG_NAME, "-n"},
+ {NATSCCFG_TRUNKTYPE, "--trunk-type"},
+ {NATSCCFG_MACADDRESS, "--mac-address"},
+ {NATSCCFG_IPADDRESS, "--ip-address"},
+ {NATSCCFG_NETMASK, "--netmask"},
+ {NATSCCFG_PORTFORWARD4, "--pf4"},
+ {NATSCCFG_PORTFORWARD6, "--pf6"}
+
};
-static const ARGDEF * getArgDef(DHCPCFG type)
+static const ARGDEF * getArgDef(NATSCCFG type)
{
for (unsigned i = 0; i < RT_ELEMENTS(g_aArgDefs); i++)
if (g_aArgDefs[i].Type == type)
@@ -59,26 +52,26 @@ static const ARGDEF * getArgDef(DHCPCFG type)
return NULL;
}
-DHCPServerRunner::DHCPServerRunner()
+NATNetworkServiceRunner::NATNetworkServiceRunner()
{
mProcess = NIL_RTPROCESS;
- for (unsigned i = 0; i < DHCPCFG_NOTOPT_MAXVAL; i++)
+ for (unsigned i = 0; i < NATSCCFG_NOTOPT_MAXVAL; i++)
{
mOptionEnabled[i] = false;
}
}
-void DHCPServerRunner::detachFromServer()
+void NATNetworkServiceRunner::detachFromServer()
{
mProcess = NIL_RTPROCESS;
}
-int DHCPServerRunner::start()
+int NATNetworkServiceRunner::start()
{
if (isRunning())
return VINF_ALREADY_INITIALIZED;
- const char * args[DHCPCFG_NOTOPT_MAXVAL * 2];
+ const char * args[NATSCCFG_NOTOPT_MAXVAL * 2];
/* get the path to the executable */
char exePathBuf[RTPATH_MAX];
@@ -90,20 +83,20 @@ int DHCPServerRunner::start()
if (suffix)
{
suffix++;
- strcpy(suffix, DHCP_EXECUTABLE_NAME);
+ strcpy(suffix, NATSR_EXECUTABLE_NAME);
}
else
- exePath = DHCP_EXECUTABLE_NAME;
+ exePath = NATSR_EXECUTABLE_NAME;
int index = 0;
args[index++] = exePath;
- for (unsigned i = 0; i < DHCPCFG_NOTOPT_MAXVAL; i++)
+ for (unsigned i = 0; i < NATSCCFG_NOTOPT_MAXVAL; i++)
{
if (mOptionEnabled[i])
{
- const ARGDEF *pArgDef = getArgDef((DHCPCFG)i);
+ const ARGDEF *pArgDef = getArgDef((NATSCCFG)i);
if (!pArgDef)
continue;
args[index++] = pArgDef->Name; // e.g. "--network"
@@ -117,15 +110,20 @@ int DHCPServerRunner::start()
}
args[index++] = NULL;
+ RTENV env;
+ int rc = RTEnvCreate(&env);
+ AssertRCReturn(rc,rc);
+
+ RTEnvPutEx(env, "VBOX_LOG=e.l.f");
- int rc = RTProcCreate(exePath, args, RTENV_DEFAULT, 0, &mProcess);
+ rc = RTProcCreate(exePath, args, RTENV_DEFAULT, 0, &mProcess);
if (RT_FAILURE(rc))
mProcess = NIL_RTPROCESS;
-
+ RTEnvDestroy(env);
return rc;
}
-int DHCPServerRunner::stop()
+int NATNetworkServiceRunner::stop()
{
if (!isRunning())
return VINF_OBJECT_DESTROYED;
@@ -135,7 +133,7 @@ int DHCPServerRunner::stop()
return rc;
}
-bool DHCPServerRunner::isRunning()
+bool NATNetworkServiceRunner::isRunning()
{
if (mProcess == NIL_RTPROCESS)
return false;
diff --git a/src/VBox/Main/src-server/NetworkAdapterImpl.cpp b/src/VBox/Main/src-server/NetworkAdapterImpl.cpp
index c7e1fa17..e3908bb3 100644
--- a/src/VBox/Main/src-server/NetworkAdapterImpl.cpp
+++ b/src/VBox/Main/src-server/NetworkAdapterImpl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -23,6 +23,7 @@
#include "GuestOSTypeImpl.h"
#include "HostImpl.h"
#include "SystemPropertiesImpl.h"
+#include "VirtualBoxImpl.h"
#include <iprt/string.h>
#include <iprt/cpp/utils.h>
@@ -439,8 +440,7 @@ STDMETHODIMP NetworkAdapter::COMSETTER(MACAddress)(IN_BSTR aMACAddress)
return rc;
}
-STDMETHODIMP NetworkAdapter::COMGETTER(AttachmentType)(
- NetworkAttachmentType_T *aAttachmentType)
+STDMETHODIMP NetworkAdapter::COMGETTER(AttachmentType)(NetworkAttachmentType_T *aAttachmentType)
{
CheckComArgOutPointerValid(aAttachmentType);
@@ -454,8 +454,7 @@ STDMETHODIMP NetworkAdapter::COMGETTER(AttachmentType)(
return S_OK;
}
-STDMETHODIMP NetworkAdapter::COMSETTER(AttachmentType)(
- NetworkAttachmentType_T aAttachmentType)
+STDMETHODIMP NetworkAdapter::COMSETTER(AttachmentType)(NetworkAttachmentType_T aAttachmentType)
{
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
@@ -477,6 +476,14 @@ STDMETHODIMP NetworkAdapter::COMSETTER(AttachmentType)(
mData->mInternalNetwork = "intnet";
}
+ /* there must a NAT network name */
+ if (mData->mNATNetwork.isEmpty())
+ {
+ Log(("NAT network name not defined, setting to default \"NatNetwork\"\n"));
+ mData->mNATNetwork = "NatNetwork";
+ }
+
+ NetworkAttachmentType_T oldAttachmentType = mData->mAttachmentType;
mData->mAttachmentType = aAttachmentType;
m_fModified = true;
@@ -487,6 +494,12 @@ STDMETHODIMP NetworkAdapter::COMSETTER(AttachmentType)(
mParent->setModified(Machine::IsModified_NetworkAdapters);
mlock.release();
+ if (oldAttachmentType == NetworkAttachmentType_NATNetwork)
+ checkAndSwitchFromNatNetworking(mData->mNATNetwork.raw());
+
+ if (aAttachmentType == NetworkAttachmentType_NATNetwork)
+ switchToNatNetworking(mData->mNATNetwork.raw());
+
/* Adapt the CFGM logic and notify the guest => changeAdapter=TRUE. */
mParent->onNetworkAdapterChange(this, TRUE);
}
@@ -525,6 +538,15 @@ STDMETHODIMP NetworkAdapter::COMSETTER(BridgedInterface)(IN_BSTR aBridgedInterfa
if (mData->mBridgedInterface != aBridgedInterface)
{
+ /* if an empty/null string is to be set, bridged interface must be
+ * turned off */
+ if ( (aBridgedInterface == NULL || *aBridgedInterface == '\0')
+ && mData->mAttachmentType == NetworkAttachmentType_Bridged)
+ {
+ return setError(E_FAIL,
+ tr("Empty or null bridged interface name is not valid"));
+ }
+
mData.backup();
mData->mBridgedInterface = aBridgedInterface;
@@ -576,6 +598,15 @@ STDMETHODIMP NetworkAdapter::COMSETTER(HostOnlyInterface)(IN_BSTR aHostOnlyInter
if (mData->mHostOnlyInterface != aHostOnlyInterface)
{
+ /* if an empty/null string is to be set, host only interface must be
+ * turned off */
+ if ( (aHostOnlyInterface == NULL || *aHostOnlyInterface == '\0')
+ && mData->mAttachmentType == NetworkAttachmentType_HostOnly)
+ {
+ return setError(E_FAIL,
+ tr("Empty or null host only interface name is not valid"));
+ }
+
mData.backup();
mData->mHostOnlyInterface = aHostOnlyInterface;
@@ -683,7 +714,19 @@ STDMETHODIMP NetworkAdapter::COMSETTER(NATNetwork)(IN_BSTR aNATNetwork)
if (mData->mNATNetwork != aNATNetwork)
{
+
+ /* if an empty/null string is to be set, host only interface must be
+ * turned off */
+ if ( (aNATNetwork == NULL || *aNATNetwork == '\0')
+ && mData->mAttachmentType == NetworkAttachmentType_NATNetwork)
+ {
+ return setError(E_FAIL,
+ tr("Empty or null NAT network name is not valid"));
+ }
+
mData.backup();
+
+ Bstr oldNatNetworkName = mData->mNATNetwork;
mData->mNATNetwork = aNATNetwork;
m_fModified = true;
@@ -694,9 +737,14 @@ STDMETHODIMP NetworkAdapter::COMSETTER(NATNetwork)(IN_BSTR aNATNetwork)
mParent->setModified(Machine::IsModified_NetworkAdapters);
mlock.release();
- /* Changing the NAT network isn't allowed during runtime, therefore
- * no immediate replug in CFGM logic => changeAdapter=FALSE */
- mParent->onNetworkAdapterChange(this, FALSE);
+ checkAndSwitchFromNatNetworking(oldNatNetworkName.raw());
+
+ switchToNatNetworking(aNATNetwork);
+
+ /* When changing the host adapter, adapt the CFGM logic to make this
+ * change immediately effect and to notify the guest that the network
+ * might have changed, therefore changeAdapter=TRUE. */
+ mParent->onNetworkAdapterChange(this, TRUE);
}
return S_OK;
@@ -1208,6 +1256,7 @@ HRESULT NetworkAdapter::loadSettings(BandwidthControl *bwctl,
mData->mHostOnlyInterface = data.strHostOnlyName;
mData->mGenericDriver = data.strGenericDriver;
mData->mGenericProperties = data.genericProperties;
+ mData->mNATNetwork = data.strNATNetworkName;
// leave the lock before setting attachment type
alock.release();
@@ -1268,6 +1317,8 @@ HRESULT NetworkAdapter::saveSettings(settings::NetworkAdapter &data)
data.strGenericDriver = mData->mGenericDriver;
data.genericProperties = mData->mGenericProperties;
+ data.strNATNetworkName = mData->mNATNetwork;
+
// after saving settings, we are no longer different from the XML on disk
m_fModified = false;
@@ -1511,4 +1562,48 @@ void NetworkAdapter::updateBandwidthGroup(BandwidthGroup *aBwGroup)
LogFlowThisFuncLeave();
}
+
+
+HRESULT NetworkAdapter::checkAndSwitchFromNatNetworking(IN_BSTR networkName)
+{
+ MachineState_T state;
+
+ HRESULT hrc = mParent->COMGETTER(State)(&state);
+ if (FAILED(hrc))
+ return hrc;
+
+ if (state == MachineState_Running)
+ {
+ Bstr bstrName;
+ hrc = mParent->COMGETTER(Name)(bstrName.asOutParam());
+ LogRel(("VM '%ls' stops using NAT network '%ls'\n", bstrName.raw(), networkName));
+ int natCount = mParent->getVirtualBox()->natNetworkRefDec(networkName);
+ if (natCount == -1)
+ return E_INVALIDARG; /* no such network */
+ }
+
+ return S_OK;
+}
+
+
+HRESULT NetworkAdapter::switchToNatNetworking(IN_BSTR aNatNetworkName)
+{
+ MachineState_T state;
+
+ HRESULT hrc = mParent->COMGETTER(State)(&state);
+ if (FAILED(hrc))
+ return hrc;
+
+ if (state == MachineState_Running)
+ {
+ Bstr bstrName;
+ hrc = mParent->COMGETTER(Name)(bstrName.asOutParam());
+ LogRel(("VM '%ls' starts using NAT network '%ls'\n", bstrName.raw(), aNatNetworkName));
+ int natCount = mParent->getVirtualBox()->natNetworkRefInc(aNatNetworkName);
+ if (natCount == -1)
+ return E_INVALIDARG; /* not found */
+ }
+
+ return S_OK;
+}
/* vi: set tabstop=4 shiftwidth=4 expandtab: */
diff --git a/src/VBox/Main/src-server/NetworkServiceRunner.cpp b/src/VBox/Main/src-server/NetworkServiceRunner.cpp
new file mode 100644
index 00000000..14610e5a
--- /dev/null
+++ b/src/VBox/Main/src-server/NetworkServiceRunner.cpp
@@ -0,0 +1,138 @@
+/* $Id: NetworkServiceRunner.cpp $ */
+/** @file
+ * VirtualBox Main - interface for VBox DHCP server
+ */
+
+/*
+ * Copyright (C) 2009-2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include <map>
+#include <string>
+#include "NetworkServiceRunner.h"
+#include <iprt/process.h>
+#include <iprt/param.h>
+#include <iprt/env.h>
+
+
+const std::string NetworkServiceRunner::kNsrKeyName = "--name";
+const std::string NetworkServiceRunner::kNsrKeyNetwork = "--network";
+const std::string NetworkServiceRunner::kNsrKeyTrunkType = "--trunk-type";
+const std::string NetworkServiceRunner::kNsrTrunkName = "--trunk-name";
+const std::string NetworkServiceRunner::kNsrMacAddress = "--mac-address";
+const std::string NetworkServiceRunner::kNsrIpAddress = "--ip-address";
+const std::string NetworkServiceRunner::kNsrIpNetmask = "--netmask";
+const std::string NetworkServiceRunner::kNsrKeyNeedMain = "--need-main";
+
+struct NetworkServiceRunner::Data
+{
+ Data(const char* aProcName):mProcName(aProcName), mProcess(NIL_RTPROCESS){}
+ const char *mProcName;
+ RTPROCESS mProcess;
+ std::map<std::string, std::string> mOptions;
+};
+
+NetworkServiceRunner::NetworkServiceRunner(const char *aProcName)
+{
+ m = new NetworkServiceRunner::Data(aProcName);
+
+}
+
+
+NetworkServiceRunner::~NetworkServiceRunner()
+{
+ stop();
+ delete m;
+ m = NULL;
+}
+
+
+int NetworkServiceRunner::setOption(const std::string& key, const std::string& val)
+{
+ m->mOptions.insert(std::map<std::string, std::string>::value_type(key, val));
+ return VINF_SUCCESS;
+}
+
+
+void NetworkServiceRunner::detachFromServer()
+{
+ m->mProcess = NIL_RTPROCESS;
+}
+
+
+int NetworkServiceRunner::start()
+{
+ if (isRunning())
+ return VINF_ALREADY_INITIALIZED;
+
+ const char * args[10*2];
+
+ AssertReturn(m->mOptions.size() < 10, VERR_INTERNAL_ERROR);
+
+ /* get the path to the executable */
+ char exePathBuf[RTPATH_MAX];
+ const char *exePath = RTProcGetExecutablePath(exePathBuf, RTPATH_MAX);
+ char *substrSl = strrchr(exePathBuf, '/');
+ char *substrBs = strrchr(exePathBuf, '\\');
+ char *suffix = substrSl ? substrSl : substrBs;
+
+ if (suffix)
+ {
+ suffix++;
+ strcpy(suffix, m->mProcName);
+ }
+
+ int index = 0;
+
+ args[index++] = exePath;
+
+ std::map<std::string, std::string>::const_iterator it;
+ for(it = m->mOptions.begin(); it != m->mOptions.end(); ++it)
+ {
+ args[index++] = it->first.c_str();
+ args[index++] = it->second.c_str();
+ }
+
+ args[index++] = NULL;
+
+ int rc = RTProcCreate(suffix ? exePath : m->mProcName, args, RTENV_DEFAULT, 0, &m->mProcess);
+ if (RT_FAILURE(rc))
+ m->mProcess = NIL_RTPROCESS;
+
+ return rc;
+}
+
+
+int NetworkServiceRunner::stop()
+{
+ if (!isRunning())
+ return VINF_OBJECT_DESTROYED;
+
+ int rc = RTProcTerminate(m->mProcess);
+ RTProcWait(m->mProcess, RTPROCWAIT_FLAGS_BLOCK, NULL);
+ m->mProcess = NIL_RTPROCESS;
+ return rc;
+}
+
+bool NetworkServiceRunner::isRunning()
+{
+ if (m->mProcess == NIL_RTPROCESS)
+ return false;
+
+ RTPROCSTATUS status;
+ int rc = RTProcWait(m->mProcess, RTPROCWAIT_FLAGS_NOBLOCK, &status);
+
+ if (rc == VERR_PROCESS_RUNNING)
+ return true;
+
+ m->mProcess = NIL_RTPROCESS;
+ return false;
+}
diff --git a/src/VBox/Main/src-server/ParallelPortImpl.cpp b/src/VBox/Main/src-server/ParallelPortImpl.cpp
index 56743a08..e9ce1d0d 100644
--- a/src/VBox/Main/src-server/ParallelPortImpl.cpp
+++ b/src/VBox/Main/src-server/ParallelPortImpl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Main/src-server/Performance.cpp b/src/VBox/Main/src-server/Performance.cpp
index 465bfa1c..41ace847 100644
--- a/src/VBox/Main/src-server/Performance.cpp
+++ b/src/VBox/Main/src-server/Performance.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -24,8 +24,12 @@
#ifndef VBOX_COLLECTOR_TEST_CASE
#include "VirtualBoxImpl.h"
#include "MachineImpl.h"
+#include "MediumImpl.h"
+#include "AutoCaller.h"
#endif
#include "Performance.h"
+#include "HostNetworkInterfaceImpl.h"
+#include "netif.h"
#include <VBox/com/array.h>
#include <VBox/com/ptr.h>
@@ -45,47 +49,57 @@ using namespace pm;
int CollectorHAL::getHostCpuLoad(ULONG * /* user */, ULONG * /* kernel */, ULONG * /* idle */)
{
- return E_NOTIMPL;
+ return VERR_NOT_IMPLEMENTED;
}
int CollectorHAL::getProcessCpuLoad(RTPROCESS /* process */, ULONG * /* user */, ULONG * /* kernel */)
{
- return E_NOTIMPL;
+ return VERR_NOT_IMPLEMENTED;
}
int CollectorHAL::getRawHostCpuLoad(uint64_t * /* user */, uint64_t * /* kernel */, uint64_t * /* idle */)
{
- return E_NOTIMPL;
+ return VERR_NOT_IMPLEMENTED;
}
int CollectorHAL::getRawHostNetworkLoad(const char * /* name */, uint64_t * /* rx */, uint64_t * /* tx */)
{
- return E_NOTIMPL;
+ return VERR_NOT_IMPLEMENTED;
}
int CollectorHAL::getRawHostDiskLoad(const char * /* name */, uint64_t * /* disk_ms */, uint64_t * /* total_ms */)
{
- return E_NOTIMPL;
+ return VERR_NOT_IMPLEMENTED;
}
int CollectorHAL::getRawProcessCpuLoad(RTPROCESS /* process */, uint64_t * /* user */, uint64_t * /* kernel */, uint64_t * /* total */)
{
- return E_NOTIMPL;
+ return VERR_NOT_IMPLEMENTED;
}
int CollectorHAL::getHostMemoryUsage(ULONG * /* total */, ULONG * /* used */, ULONG * /* available */)
{
- return E_NOTIMPL;
+ return VERR_NOT_IMPLEMENTED;
}
int CollectorHAL::getHostFilesystemUsage(const char * /* name */, ULONG * /* total */, ULONG * /* used */, ULONG * /* available */)
{
- return E_NOTIMPL;
+ return VERR_NOT_IMPLEMENTED;
+}
+
+int CollectorHAL::getHostDiskSize(const char * /* name */, uint64_t * /* size */)
+{
+ return VERR_NOT_IMPLEMENTED;
}
int CollectorHAL::getProcessMemoryUsage(RTPROCESS /* process */, ULONG * /* used */)
{
- return E_NOTIMPL;
+ return VERR_NOT_IMPLEMENTED;
+}
+
+int CollectorHAL::getDiskListByFs(const char * /* name */, DiskList& /* listUsage */, DiskList& /* listLoad */)
+{
+ return VERR_NOT_IMPLEMENTED;
}
/* Generic implementations */
@@ -169,7 +183,7 @@ CollectorGuestRequest* CollectorGuestQueue::pop()
return NULL;
}
-int CGRQEnable::execute()
+HRESULT CGRQEnable::execute()
{
Assert(mCGuest);
return mCGuest->enableInternal(mMask);
@@ -184,7 +198,7 @@ void CGRQEnable::debugPrint(void *aObject, const char *aFunction, const char *aT
aObject, aFunction, mMask, aText));
}
-int CGRQDisable::execute()
+HRESULT CGRQDisable::execute()
{
Assert(mCGuest);
return mCGuest->disableInternal(mMask);
@@ -199,7 +213,7 @@ void CGRQDisable::debugPrint(void *aObject, const char *aFunction, const char *a
aObject, aFunction, mMask, aText));
}
-int CGRQAbort::execute()
+HRESULT CGRQAbort::execute()
{
return E_ABORT;
}
@@ -217,7 +231,7 @@ CollectorGuest::CollectorGuest(Machine *machine, RTPROCESS process) :
mUnregistered(false), mEnabled(false), mValid(false), mMachine(machine), mProcess(process),
mCpuUser(0), mCpuKernel(0), mCpuIdle(0),
mMemTotal(0), mMemFree(0), mMemBalloon(0), mMemShared(0), mMemCache(0), mPageTotal(0),
- mAllocVMM(0), mFreeVMM(0), mBalloonedVMM(0), mSharedVMM(0)
+ mAllocVMM(0), mFreeVMM(0), mBalloonedVMM(0), mSharedVMM(0), mVmNetRx(0), mVmNetTx(0)
{
Assert(mMachine);
/* cannot use ComObjPtr<Machine> in Performance.h, do it manually */
@@ -267,7 +281,7 @@ int CollectorGuest::disable(ULONG mask)
return enqueueRequest(new CGRQDisable(mask));
}
-int CollectorGuest::enableInternal(ULONG mask)
+HRESULT CollectorGuest::enableInternal(ULONG mask)
{
HRESULT ret = S_OK;
@@ -306,7 +320,7 @@ int CollectorGuest::enableInternal(ULONG mask)
this, __PRETTY_FUNCTION__, SUCCEEDED(ret)?"success":"failed"));
}
}
- if ((mask & GUESTSTATS_VMMRAM) == GUESTSTATS_VMMRAM)
+ if ((mask & VMSTATS_VMM_RAM) == VMSTATS_VMM_RAM)
enableVMMStats(true);
mEnabled |= mask;
@@ -318,7 +332,7 @@ int CollectorGuest::disableInternal(ULONG mask)
if (!(mEnabled & mask))
return E_UNEXPECTED;
- if ((mask & GUESTSTATS_VMMRAM) == GUESTSTATS_VMMRAM)
+ if ((mask & VMSTATS_VMM_RAM) == VMSTATS_VMM_RAM)
enableVMMStats(false);
mEnabled &= ~mask;
if (!mEnabled)
@@ -328,7 +342,7 @@ int CollectorGuest::disableInternal(ULONG mask)
NOREF(ret);
LogAleksey(("{%p} " LOG_FN_FMT ": Set guest statistics update interval to 0 sec (%s)\n",
this, __PRETTY_FUNCTION__, SUCCEEDED(ret)?"success":"failed"));
- invalidate(GUESTSTATS_ALL);
+ invalidate(VMSTATS_ALL);
}
return S_OK;
@@ -353,15 +367,16 @@ void CollectorGuest::updateStats(ULONG aValidStats, ULONG aCpuUser,
ULONG aMemBalloon, ULONG aMemShared,
ULONG aMemCache, ULONG aPageTotal,
ULONG aAllocVMM, ULONG aFreeVMM,
- ULONG aBalloonedVMM, ULONG aSharedVMM)
+ ULONG aBalloonedVMM, ULONG aSharedVMM,
+ ULONG aVmNetRx, ULONG aVmNetTx)
{
- if ((aValidStats & GUESTSTATS_CPULOAD) == GUESTSTATS_CPULOAD)
+ if ((aValidStats & VMSTATS_GUEST_CPULOAD) == VMSTATS_GUEST_CPULOAD)
{
mCpuUser = aCpuUser;
mCpuKernel = aCpuKernel,
mCpuIdle = aCpuIdle;
}
- if ((aValidStats & GUESTSTATS_RAMUSAGE) == GUESTSTATS_RAMUSAGE)
+ if ((aValidStats & VMSTATS_GUEST_RAMUSAGE) == VMSTATS_GUEST_RAMUSAGE)
{
mMemTotal = aMemTotal;
mMemFree = aMemFree;
@@ -370,13 +385,18 @@ void CollectorGuest::updateStats(ULONG aValidStats, ULONG aCpuUser,
mMemCache = aMemCache;
mPageTotal = aPageTotal;
}
- if ((aValidStats & GUESTSTATS_VMMRAM) == GUESTSTATS_VMMRAM)
+ if ((aValidStats & VMSTATS_VMM_RAM) == VMSTATS_VMM_RAM)
{
mAllocVMM = aAllocVMM;
mFreeVMM = aFreeVMM;
mBalloonedVMM = aBalloonedVMM;
mSharedVMM = aSharedVMM;
}
+ if ((aValidStats & VMSTATS_NET_RATE) == VMSTATS_NET_RATE)
+ {
+ mVmNetRx = aVmNetRx;
+ mVmNetTx = aVmNetTx;
+ }
mValid = aValidStats;
}
@@ -446,7 +466,7 @@ void CollectorGuestManager::unregisterGuest(CollectorGuest* pGuest)
{
/* Found the guest already collecting stats, elect it */
mVMMStatsProvider = *it;
- rc = mVMMStatsProvider->enqueueRequest(new CGRQEnable(GUESTSTATS_VMMRAM));
+ rc = mVMMStatsProvider->enqueueRequest(new CGRQEnable(VMSTATS_VMM_RAM));
if (FAILED(rc))
{
/* This is not a good candidate -- try to find another */
@@ -466,8 +486,8 @@ void CollectorGuestManager::unregisterGuest(CollectorGuest* pGuest)
continue;
mVMMStatsProvider = *it;
- //mVMMStatsProvider->enable(GUESTSTATS_VMMRAM);
- rc = mVMMStatsProvider->enqueueRequest(new CGRQEnable(GUESTSTATS_VMMRAM));
+ //mVMMStatsProvider->enable(VMSTATS_VMM_RAM);
+ rc = mVMMStatsProvider->enqueueRequest(new CGRQEnable(VMSTATS_VMM_RAM));
if (SUCCEEDED(rc))
break;
/* This was not a good candidate -- try to find another */
@@ -508,7 +528,7 @@ int CollectorGuestManager::enqueueRequest(CollectorGuestRequest *aRequest)
*/
if (aRequest->getGuest() && aRequest->getGuest() == mGuestBeingCalled)
{
- /*
+ /*
* Before we can declare a guest blocked we need to wait for a while
* and then check again as it may never had a chance to process
* the previous request. Half a second is an eternity for processes
@@ -619,6 +639,12 @@ void HostCpuLoad::collect()
}
}
+void HostCpuLoadRaw::init(ULONG period, ULONG length)
+{
+ HostCpuLoad::init(period, length);
+ mHAL->getRawHostCpuLoad(&mUserPrev, &mKernelPrev, &mIdlePrev);
+}
+
void HostCpuLoadRaw::preCollect(CollectorHints& hints, uint64_t /* iTick */)
{
hints.collectHostCpuLoad();
@@ -659,13 +685,50 @@ void HostCpuLoadRaw::collect()
}
}
+#ifndef VBOX_COLLECTOR_TEST_CASE
+static bool getLinkSpeed(const char *szShortName, uint32_t *pSpeed)
+{
+ NETIFSTATUS enmState = NETIF_S_UNKNOWN;
+ int rc = NetIfGetState(szShortName, &enmState);
+ if (RT_FAILURE(rc))
+ return false;
+ if (enmState != NETIF_S_UP)
+ *pSpeed = 0;
+ else
+ {
+ rc = NetIfGetLinkSpeed(szShortName, pSpeed);
+ if (RT_FAILURE(rc))
+ return false;
+ }
+ return true;
+}
+
+void HostNetworkSpeed::init(ULONG period, ULONG length)
+{
+ mPeriod = period;
+ mLength = length;
+ mLinkSpeed->init(length);
+ /*
+ * Retrieve the link speed now as it may be wrong if the metric was
+ * registered at boot (see @bugref{6613}).
+ */
+ getLinkSpeed(mShortName.c_str(), &mSpeed);
+}
+
void HostNetworkLoadRaw::init(ULONG period, ULONG length)
{
mPeriod = period;
mLength = length;
mRx->init(mLength);
mTx->init(mLength);
- int rc = mHAL->getRawHostNetworkLoad(mShortName.c_str(), &mRxPrev, &mTxPrev);
+ /*
+ * Retrieve the link speed now as it may be wrong if the metric was
+ * registered at boot (see @bugref{6613}).
+ */
+ uint32_t uSpeedMbit = 65535;
+ if (getLinkSpeed(mShortName.c_str(), &uSpeedMbit))
+ mSpeed = (uint64_t)uSpeedMbit * (1000000/8); /* Convert to bytes/sec */
+ /*int rc =*/ mHAL->getRawHostNetworkLoad(mShortName.c_str(), &mRxPrev, &mTxPrev);
//AssertRC(rc);
}
@@ -686,25 +749,23 @@ void HostNetworkLoadRaw::preCollect(CollectorHints& /* hints */, uint64_t /* iTi
void HostNetworkLoadRaw::collect()
{
- uint64_t rx, tx;
+ uint64_t rx = mRxPrev;
+ uint64_t tx = mTxPrev;
+ if (RT_UNLIKELY(mSpeed * getPeriod() == 0))
+ {
+ LogFlowThisFunc(("Check cable for %s! speed=%llu period=%d.\n", mShortName.c_str(), mSpeed, getPeriod()));
+ /* We do not collect host network metrics for unplugged interfaces! */
+ return;
+ }
mRc = mHAL->getRawHostNetworkLoad(mShortName.c_str(), &rx, &tx);
if (RT_SUCCESS(mRc))
{
uint64_t rxDiff = rx - mRxPrev;
uint64_t txDiff = tx - mTxPrev;
- if (RT_UNLIKELY(mSpeed * getPeriod() == 0))
- {
- LogFlowThisFunc(("Check cable for %s! speed=%llu period=%d.\n", mShortName.c_str(), mSpeed, getPeriod()));
- mRx->put(0);
- mTx->put(0);
- }
- else
- {
- mRx->put((ULONG)(PM_NETWORK_LOAD_MULTIPLIER * rxDiff / (mSpeed * getPeriod())));
- mTx->put((ULONG)(PM_NETWORK_LOAD_MULTIPLIER * txDiff / (mSpeed * getPeriod())));
- }
+ mRx->put((ULONG)(PM_NETWORK_LOAD_MULTIPLIER * rxDiff / (mSpeed * getPeriod())));
+ mTx->put((ULONG)(PM_NETWORK_LOAD_MULTIPLIER * txDiff / (mSpeed * getPeriod())));
mRxPrev = rx;
mTxPrev = tx;
@@ -713,6 +774,7 @@ void HostNetworkLoadRaw::collect()
LogFlowThisFunc(("Failed to collect data: %Rrc (%d)."
" Will update the list of interfaces...\n", mRc,mRc));
}
+#endif /* !VBOX_COLLECTOR_TEST_CASE */
void HostDiskLoadRaw::init(ULONG period, ULONG length)
{
@@ -815,7 +877,6 @@ void HostRamUsage::collect()
mTotal->put(total);
mUsed->put(used);
mAvailable->put(available);
-
}
}
@@ -841,10 +902,28 @@ void HostFilesystemUsage::collect()
mTotal->put(total);
mUsed->put(used);
mAvailable->put(available);
-
}
}
+void HostDiskUsage::init(ULONG period, ULONG length)
+{
+ mPeriod = period;
+ mLength = length;
+ mTotal->init(mLength);
+}
+
+void HostDiskUsage::preCollect(CollectorHints& /* hints */, uint64_t /* iTick */)
+{
+}
+
+void HostDiskUsage::collect()
+{
+ uint64_t total;
+ int rc = mHAL->getHostDiskSize(mDiskName.c_str(), &total);
+ if (RT_SUCCESS(rc))
+ mTotal->put((ULONG)(total / _1M));
+}
+
#ifndef VBOX_COLLECTOR_TEST_CASE
void HostRamVmm::init(ULONG period, ULONG length)
{
@@ -861,7 +940,7 @@ int HostRamVmm::enable()
int rc = S_OK;
CollectorGuest *provider = mCollectorGuestManager->getVMMStatsProvider();
if (provider)
- rc = provider->enable(GUESTSTATS_VMMRAM);
+ rc = provider->enable(VMSTATS_VMM_RAM);
BaseMetric::enable();
return rc;
}
@@ -872,7 +951,7 @@ int HostRamVmm::disable()
BaseMetric::disable();
CollectorGuest *provider = mCollectorGuestManager->getVMMStatsProvider();
if (provider)
- rc = provider->disable(GUESTSTATS_VMMRAM);
+ rc = provider->disable(VMSTATS_VMM_RAM);
return rc;
}
@@ -888,15 +967,15 @@ void HostRamVmm::collect()
{
LogAleksey(("{%p} " LOG_FN_FMT ": provider=%p enabled=%s valid=%s...\n",
this, __PRETTY_FUNCTION__, provider, provider->isEnabled()?"y":"n",
- provider->isValid(GUESTSTATS_VMMRAM)?"y":"n"));
- if (provider->isValid(GUESTSTATS_VMMRAM))
+ provider->isValid(VMSTATS_VMM_RAM)?"y":"n"));
+ if (provider->isValid(VMSTATS_VMM_RAM))
{
/* Provider is ready, get updated stats */
mAllocCurrent = provider->getAllocVMM();
mFreeCurrent = provider->getFreeVMM();
mBalloonedCurrent = provider->getBalloonedVMM();
mSharedCurrent = provider->getSharedVMM();
- provider->invalidate(GUESTSTATS_VMMRAM);
+ provider->invalidate(VMSTATS_VMM_RAM);
}
/*
* Note that if there are no new values from the provider we will use
@@ -994,6 +1073,76 @@ void MachineRamUsage::collect()
#ifndef VBOX_COLLECTOR_TEST_CASE
+void MachineDiskUsage::init(ULONG period, ULONG length)
+{
+ mPeriod = period;
+ mLength = length;
+ mUsed->init(mLength);
+}
+
+void MachineDiskUsage::preCollect(CollectorHints& /* hints */, uint64_t /* iTick */)
+{
+}
+
+void MachineDiskUsage::collect()
+{
+ ULONG used = 0;
+
+ for (MediaList::iterator it = mDisks.begin(); it != mDisks.end(); ++it)
+ {
+ ComObjPtr<Medium> pMedium = *it;
+
+ /* just in case */
+ AssertStmt(!pMedium.isNull(), continue);
+
+ AutoCaller localAutoCaller(pMedium);
+ if (FAILED(localAutoCaller.rc())) continue;
+
+ AutoReadLock local_alock(pMedium COMMA_LOCKVAL_SRC_POS);
+
+ used += (ULONG)(pMedium->getSize() / _1M);
+ }
+
+ mUsed->put(used);
+}
+
+void MachineNetRate::init(ULONG period, ULONG length)
+{
+ mPeriod = period;
+ mLength = length;
+
+ mRx->init(mLength);
+ mTx->init(mLength);
+}
+
+void MachineNetRate::collect()
+{
+ if (mCGuest->isValid(VMSTATS_NET_RATE))
+ {
+ mRx->put(mCGuest->getVmNetRx());
+ mTx->put(mCGuest->getVmNetTx());
+ mCGuest->invalidate(VMSTATS_NET_RATE);
+ }
+}
+
+int MachineNetRate::enable()
+{
+ int rc = mCGuest->enable(VMSTATS_NET_RATE);
+ BaseMetric::enable();
+ return rc;
+}
+
+int MachineNetRate::disable()
+{
+ BaseMetric::disable();
+ return mCGuest->disable(VMSTATS_NET_RATE);
+}
+
+void MachineNetRate::preCollect(CollectorHints& hints, uint64_t /* iTick */)
+{
+ hints.collectGuestStats(mCGuest->getProcess());
+}
+
void GuestCpuLoad::init(ULONG period, ULONG length)
{
mPeriod = period;
@@ -1011,18 +1160,18 @@ void GuestCpuLoad::preCollect(CollectorHints& hints, uint64_t /* iTick */)
void GuestCpuLoad::collect()
{
- if (mCGuest->isValid(GUESTSTATS_CPULOAD))
+ if (mCGuest->isValid(VMSTATS_GUEST_CPULOAD))
{
mUser->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * mCGuest->getCpuUser()) / 100);
mKernel->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * mCGuest->getCpuKernel()) / 100);
mIdle->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * mCGuest->getCpuIdle()) / 100);
- mCGuest->invalidate(GUESTSTATS_CPULOAD);
+ mCGuest->invalidate(VMSTATS_GUEST_CPULOAD);
}
}
int GuestCpuLoad::enable()
{
- int rc = mCGuest->enable(GUESTSTATS_CPULOAD);
+ int rc = mCGuest->enable(VMSTATS_GUEST_CPULOAD);
BaseMetric::enable();
return rc;
}
@@ -1030,7 +1179,7 @@ int GuestCpuLoad::enable()
int GuestCpuLoad::disable()
{
BaseMetric::disable();
- return mCGuest->disable(GUESTSTATS_CPULOAD);
+ return mCGuest->disable(VMSTATS_GUEST_CPULOAD);
}
void GuestRamUsage::init(ULONG period, ULONG length)
@@ -1048,7 +1197,7 @@ void GuestRamUsage::init(ULONG period, ULONG length)
void GuestRamUsage::collect()
{
- if (mCGuest->isValid(GUESTSTATS_RAMUSAGE))
+ if (mCGuest->isValid(VMSTATS_GUEST_RAMUSAGE))
{
mTotal->put(mCGuest->getMemTotal());
mFree->put(mCGuest->getMemFree());
@@ -1056,13 +1205,13 @@ void GuestRamUsage::collect()
mShared->put(mCGuest->getMemShared());
mCache->put(mCGuest->getMemCache());
mPagedTotal->put(mCGuest->getPageTotal());
- mCGuest->invalidate(GUESTSTATS_RAMUSAGE);
+ mCGuest->invalidate(VMSTATS_GUEST_RAMUSAGE);
}
}
int GuestRamUsage::enable()
{
- int rc = mCGuest->enable(GUESTSTATS_RAMUSAGE);
+ int rc = mCGuest->enable(VMSTATS_GUEST_RAMUSAGE);
BaseMetric::enable();
return rc;
}
@@ -1070,7 +1219,7 @@ int GuestRamUsage::enable()
int GuestRamUsage::disable()
{
BaseMetric::disable();
- return mCGuest->disable(GUESTSTATS_RAMUSAGE);
+ return mCGuest->disable(VMSTATS_GUEST_RAMUSAGE);
}
void GuestRamUsage::preCollect(CollectorHints& hints, uint64_t /* iTick */)
diff --git a/src/VBox/Main/src-server/PerformanceImpl.cpp b/src/VBox/Main/src-server/PerformanceImpl.cpp
index b233f0a7..87ad1c4c 100644
--- a/src/VBox/Main/src-server/PerformanceImpl.cpp
+++ b/src/VBox/Main/src-server/PerformanceImpl.cpp
@@ -6,7 +6,7 @@
*/
/*
- * Copyright (C) 2008-2010 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Main/src-server/ProgressProxyImpl.cpp b/src/VBox/Main/src-server/ProgressProxyImpl.cpp
index a6628760..60750d6f 100644
--- a/src/VBox/Main/src-server/ProgressProxyImpl.cpp
+++ b/src/VBox/Main/src-server/ProgressProxyImpl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Main/src-server/SerialPortImpl.cpp b/src/VBox/Main/src-server/SerialPortImpl.cpp
index 81234c49..5bbf4ba3 100644
--- a/src/VBox/Main/src-server/SerialPortImpl.cpp
+++ b/src/VBox/Main/src-server/SerialPortImpl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Main/src-server/SnapshotImpl.cpp b/src/VBox/Main/src-server/SnapshotImpl.cpp
index 4740b122..411cdd56 100644
--- a/src/VBox/Main/src-server/SnapshotImpl.cpp
+++ b/src/VBox/Main/src-server/SnapshotImpl.cpp
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -29,6 +29,7 @@
// to remove them and put that code in shared code in MachineImplcpp
#include "SharedFolderImpl.h"
#include "USBControllerImpl.h"
+#include "USBDeviceFiltersImpl.h"
#include "VirtualBoxImpl.h"
#include "AutoCaller.h"
@@ -41,6 +42,7 @@
#include <VBox/settings.h>
+
////////////////////////////////////////////////////////////////////////////////
//
// Snapshot private data definition
@@ -113,7 +115,7 @@ HRESULT Snapshot::init(VirtualBox *aVirtualBox,
{
LogFlowThisFunc(("uuid=%s aParent->uuid=%s\n", aId.toString().c_str(), (aParent) ? aParent->m->uuid.toString().c_str() : ""));
- ComAssertRet(!aId.isEmpty() && !aName.isEmpty() && aMachine, E_INVALIDARG);
+ ComAssertRet(!aId.isZero() && aId.isValid() && !aName.isEmpty() && aMachine, E_INVALIDARG);
/* Enclose the state transition NotReady->InInit->Ready */
AutoInitSpan autoInitSpan(this);
@@ -327,7 +329,8 @@ STDMETHODIMP Snapshot::COMSETTER(Name)(IN_BSTR aName)
// prohibit setting a UUID only as the machine name, or else it can
// never be found by findMachine()
Guid test(aName);
- if (test.isNotEmpty())
+
+ if (!test.isZero() && test.isValid())
return setError(E_INVALIDARG, tr("A machine cannot have a UUID as its name"));
AutoCaller autoCaller(this);
@@ -493,6 +496,31 @@ const Utf8Str& Snapshot::getStateFilePath() const
}
/**
+ * Returns the depth in the snapshot tree for this snapshot.
+ *
+ * @note takes the snapshot tree lock
+ */
+
+uint32_t Snapshot::getDepth()
+{
+ AutoCaller autoCaller(this);
+ AssertComRC(autoCaller.rc());
+
+ // snapshots tree is protected by machine lock
+ AutoReadLock alock(m->pMachine COMMA_LOCKVAL_SRC_POS);
+
+ uint32_t cDepth = 0;
+ ComObjPtr<Snapshot> pSnap(this);
+ while (!pSnap.isNull())
+ {
+ pSnap = pSnap->m->pParent;
+ cDepth++;
+ }
+
+ return cDepth;
+}
+
+/**
* Returns the number of direct child snapshots, without grandchildren.
* Does not recurse.
* @return
@@ -788,11 +816,19 @@ HRESULT Snapshot::saveSnapshotImpl(settings::Snapshot &data, bool aAttrsOnly)
it != m->llChildren.end();
++it)
{
- settings::Snapshot snap;
- rc = (*it)->saveSnapshotImpl(snap, aAttrsOnly);
- if (FAILED(rc)) return rc;
+ // Use the heap to reduce the stack footprint. Each recursion needs
+ // over 1K, and there can be VMs with deeply nested snapshots. The
+ // stack can be quite small, especially with XPCOM.
- data.llChildSnapshots.push_back(snap);
+ settings::Snapshot *snap = new settings::Snapshot();
+ rc = (*it)->saveSnapshotImpl(*snap, aAttrsOnly);
+ if (FAILED(rc))
+ {
+ delete snap;
+ return rc;
+ }
+ data.llChildSnapshots.push_back(*snap);
+ delete snap;
}
}
@@ -954,7 +990,8 @@ HRESULT SnapshotMachine::init(SessionMachine *aSessionMachine,
LogFlowThisFuncEnter();
LogFlowThisFunc(("mName={%s}\n", aSessionMachine->mUserData->s.strName.c_str()));
- AssertReturn(aSessionMachine && !Guid(aSnapshotId).isEmpty(), E_INVALIDARG);
+ Guid l_guid(aSnapshotId);
+ AssertReturn(aSessionMachine && (!l_guid.isZero() && l_guid.isValid()), E_INVALIDARG);
/* Enclose the state transition NotReady->InInit->Ready */
AutoInitSpan autoInitSpan(this);
@@ -1040,8 +1077,22 @@ HRESULT SnapshotMachine::init(SessionMachine *aSessionMachine,
unconst(mAudioAdapter).createObject();
mAudioAdapter->initCopy(this, pMachine->mAudioAdapter);
- unconst(mUSBController).createObject();
- mUSBController->initCopy(this, pMachine->mUSBController);
+ /* create copies of all USB controllers (mUSBControllerData
+ * after attaching a copy contains just references to original objects) */
+ mUSBControllers.allocate();
+ for (USBControllerList::const_iterator
+ it = aSessionMachine->mUSBControllers->begin();
+ it != aSessionMachine->mUSBControllers->end();
+ ++it)
+ {
+ ComObjPtr<USBController> ctrl;
+ ctrl.createObject();
+ ctrl->initCopy(this, *it);
+ mUSBControllers->push_back(ctrl);
+ }
+
+ unconst(mUSBDeviceFilters).createObject();
+ mUSBDeviceFilters->initCopy(this, pMachine->mUSBDeviceFilters);
mNetworkAdapters.resize(pMachine->mNetworkAdapters.size());
for (ULONG slot = 0; slot < mNetworkAdapters.size(); slot++)
@@ -1095,7 +1146,8 @@ HRESULT SnapshotMachine::initFromSettings(Machine *aMachine,
LogFlowThisFuncEnter();
LogFlowThisFunc(("mName={%s}\n", aMachine->mUserData->s.strName.c_str()));
- AssertReturn(aMachine && !Guid(aSnapshotId).isEmpty(), E_INVALIDARG);
+ Guid l_guid(aSnapshotId);
+ AssertReturn(aMachine && (!l_guid.isZero() && l_guid.isValid()), E_INVALIDARG);
/* Enclose the state transition NotReady->InInit->Ready */
AutoInitSpan autoInitSpan(this);
@@ -1122,6 +1174,7 @@ HRESULT SnapshotMachine::initFromSettings(Machine *aMachine,
mHWData.allocate();
mMediaData.allocate();
mStorageControllers.allocate();
+ mUSBControllers.allocate();
/* SSData is always unique for SnapshotMachine */
mSSData.allocate();
@@ -1138,8 +1191,8 @@ HRESULT SnapshotMachine::initFromSettings(Machine *aMachine,
unconst(mAudioAdapter).createObject();
mAudioAdapter->init(this);
- unconst(mUSBController).createObject();
- mUSBController->init(this);
+ unconst(mUSBDeviceFilters).createObject();
+ mUSBDeviceFilters->init(this);
mNetworkAdapters.resize(Global::getMaxNetworkAdapters(mHWData->mChipsetType));
for (ULONG slot = 0; slot < mNetworkAdapters.size(); slot++)
@@ -1381,7 +1434,7 @@ struct SessionMachine::DeleteSnapshotTask
*
* When the console is done, it calls SessionMachine::EndTakingSnapshot().
*
- * @note Locks mParent + this object for writing.
+ * @note Locks mParent + this object for writing.
*
* @param aInitiator in: The console on which Console::TakeSnapshot was called.
* @param aName in: The name for the new snapshot.
@@ -1416,6 +1469,14 @@ STDMETHODIMP SessionMachine::BeginTakingSnapshot(IConsole *aInitiator,
AssertReturn(mConsoleTaskData.mLastState == MachineState_Null, E_FAIL);
AssertReturn(mConsoleTaskData.mSnapshot.isNull(), E_FAIL);
+ if ( mData->mCurrentSnapshot
+ && mData->mCurrentSnapshot->getDepth() >= SETTINGS_SNAPSHOT_DEPTH_MAX)
+ {
+ return setError(VBOX_E_INVALID_OBJECT_STATE,
+ tr("Cannot take another snapshot for machine '%s', because it exceeds the maximum snapshot depth limit. Please delete some earlier snapshot which you no longer need"),
+ mUserData->s.strName.c_str());
+ }
+
if ( !fTakingSnapshotOnline
&& mData->mMachineState != MachineState_Saved
)
@@ -1435,8 +1496,16 @@ STDMETHODIMP SessionMachine::BeginTakingSnapshot(IConsole *aInitiator,
Utf8Str strStateFilePath;
/* stateFilePath is null when the machine is not online nor saved */
if (fTakingSnapshotOnline)
- // creating a new online snapshot: then we need a fresh saved state file
- composeSavedStateFilename(strStateFilePath);
+ {
+ Bstr value;
+ HRESULT rc = GetExtraData(Bstr("VBoxInternal2/ForceTakeSnapshotWithoutState").raw(),
+ value.asOutParam());
+ if (FAILED(rc) || value != "1")
+ {
+ // creating a new online snapshot: we need a fresh saved state file
+ composeSavedStateFilename(strStateFilePath);
+ }
+ }
else if (mData->mMachineState == MachineState_Saved)
// taking an online snapshot from machine in "saved" state: then use existing state file
strStateFilePath = mSSData->strStateFilePath;
@@ -1499,9 +1568,9 @@ STDMETHODIMP SessionMachine::BeginTakingSnapshot(IConsole *aInitiator,
if (FAILED(rc))
throw rc;
- // if we got this far without an error, then save the media registries
- // that got modified for the diff images
- mParent->saveModifiedRegistries();
+ // MUST NOT save the settings or the media registry here, because
+ // this causes trouble with rolling back settings if the user cancels
+ // taking the snapshot after the diff images have been created.
}
catch (HRESULT hrc)
{
@@ -1608,11 +1677,14 @@ STDMETHODIMP SessionMachine::EndTakingSnapshot(BOOL aSuccess)
/* inform callbacks */
mParent->onSnapshotTaken(mData->mUuid,
mConsoleTaskData.mSnapshot->getId());
+ machineLock.release();
}
else
{
/* delete all differencing hard disks created (this will also attach
* their parents back by rolling back mMediaData) */
+ machineLock.release();
+
rollbackMedia();
mData->mFirstSnapshot = pOldFirstSnap; // might have been changed above
@@ -1624,15 +1696,19 @@ STDMETHODIMP SessionMachine::EndTakingSnapshot(BOOL aSuccess)
// snapshot means that a new saved state file was created, which we must
// clean up now
RTFileDelete(mConsoleTaskData.mSnapshot->getStateFilePath().c_str());
+ machineLock.acquire();
+
mConsoleTaskData.mSnapshot->uninit();
+ machineLock.release();
+
}
/* clear out the snapshot data */
mConsoleTaskData.mLastState = MachineState_Null;
mConsoleTaskData.mSnapshot.setNull();
- machineLock.release();
+ /* machineLock has been released already */
mParent->saveModifiedRegistries();
@@ -2027,7 +2103,7 @@ void SessionMachine::restoreSnapshotHandler(RestoreSnapshotTask &aTask)
////////////////////////////////////////////////////////////////////////////////
/**
- * Implementation for IInternalMachineControl::deleteSnapshot().
+ * Implementation for IInternalMachineControl::DeleteSnapshot().
*
* Gets called from Console::DeleteSnapshot(), and that's basically the
* only thing Console does initially. Deleting a snapshot happens entirely on
@@ -2053,7 +2129,9 @@ STDMETHODIMP SessionMachine::DeleteSnapshot(IConsole *aInitiator,
Guid startId(aStartId);
Guid endId(aEndId);
- AssertReturn(aInitiator && !startId.isEmpty() && !endId.isEmpty(), E_INVALIDARG);
+
+ AssertReturn(aInitiator && !startId.isZero() && !endId.isZero() && startId.isValid() && endId.isValid(), E_INVALIDARG);
+
AssertReturn(aMachineState && aProgress, E_POINTER);
/** @todo implement the "and all children" and "range" variants */
@@ -2086,10 +2164,15 @@ STDMETHODIMP SessionMachine::DeleteSnapshot(IConsole *aInitiator,
size_t childrenCount = pSnapshot->getChildrenCount();
if (childrenCount > 1)
return setError(VBOX_E_INVALID_OBJECT_STATE,
- tr("Snapshot '%s' of the machine '%s' cannot be deleted. because it has %d child snapshots, which is more than the one snapshot allowed for deletion"),
+ tr("Snapshot '%s' of the machine '%s' cannot be deleted, because it has %d child snapshots, which is more than the one snapshot allowed for deletion"),
pSnapshot->getName().c_str(),
mUserData->s.strName.c_str(),
childrenCount);
+ if (pSnapshot == mData->mCurrentSnapshot && childrenCount >= 1)
+ return setError(VBOX_E_INVALID_OBJECT_STATE,
+ tr("Snapshot '%s' of the machine '%s' cannot be deleted, because it is the current snapshot and has one child snapshot"),
+ pSnapshot->getName().c_str(),
+ mUserData->s.strName.c_str());
/* If the snapshot being deleted is the current one, ensure current
* settings are committed and saved.
@@ -2215,18 +2298,20 @@ struct MediumDeleteRec
const ComObjPtr<MediumAttachment> &aOnlineMediumAttachment,
bool fMergeForward,
const ComObjPtr<Medium> &aParentForTarget,
- const MediaList &aChildrenToReparent,
+ MediumLockList *aChildrenToReparent,
bool fNeedsOnlineMerge,
- MediumLockList *aMediumLockList)
+ MediumLockList *aMediumLockList,
+ const ComPtr<IToken> &aHDLockToken)
: mpHD(aHd),
mpSource(aSource),
mpTarget(aTarget),
mpOnlineMediumAttachment(aOnlineMediumAttachment),
mfMergeForward(fMergeForward),
mpParentForTarget(aParentForTarget),
- mChildrenToReparent(aChildrenToReparent),
+ mpChildrenToReparent(aChildrenToReparent),
mfNeedsOnlineMerge(fNeedsOnlineMerge),
- mpMediumLockList(aMediumLockList)
+ mpMediumLockList(aMediumLockList),
+ mpHDLockToken(aHDLockToken)
{}
MediumDeleteRec(const ComObjPtr<Medium> &aHd,
@@ -2235,9 +2320,10 @@ struct MediumDeleteRec
const ComObjPtr<MediumAttachment> &aOnlineMediumAttachment,
bool fMergeForward,
const ComObjPtr<Medium> &aParentForTarget,
- const MediaList &aChildrenToReparent,
+ MediumLockList *aChildrenToReparent,
bool fNeedsOnlineMerge,
MediumLockList *aMediumLockList,
+ const ComPtr<IToken> &aHDLockToken,
const Guid &aMachineId,
const Guid &aSnapshotId)
: mpHD(aHd),
@@ -2246,9 +2332,10 @@ struct MediumDeleteRec
mpOnlineMediumAttachment(aOnlineMediumAttachment),
mfMergeForward(fMergeForward),
mpParentForTarget(aParentForTarget),
- mChildrenToReparent(aChildrenToReparent),
+ mpChildrenToReparent(aChildrenToReparent),
mfNeedsOnlineMerge(fNeedsOnlineMerge),
mpMediumLockList(aMediumLockList),
+ mpHDLockToken(aHDLockToken),
mMachineId(aMachineId),
mSnapshotId(aSnapshotId)
{}
@@ -2259,9 +2346,11 @@ struct MediumDeleteRec
ComObjPtr<MediumAttachment> mpOnlineMediumAttachment;
bool mfMergeForward;
ComObjPtr<Medium> mpParentForTarget;
- MediaList mChildrenToReparent;
+ MediumLockList *mpChildrenToReparent;
bool mfNeedsOnlineMerge;
MediumLockList *mpMediumLockList;
+ /** optional lock token, used only in case mpHD is not merged/deleted */
+ ComPtr<IToken> mpHDLockToken;
/* these are for reattaching the hard disk in case of a failure: */
Guid mMachineId;
Guid mSnapshotId;
@@ -2371,11 +2460,12 @@ void SessionMachine::deleteSnapshotHandler(DeleteSnapshotTask &aTask)
ComObjPtr<Medium> pSource;
bool fMergeForward = false;
ComObjPtr<Medium> pParentForTarget;
- MediaList childrenToReparent;
+ MediumLockList *pChildrenToReparent = NULL;
bool fNeedsOnlineMerge = false;
bool fOnlineMergePossible = aTask.m_fDeleteOnline;
MediumLockList *pMediumLockList = NULL;
MediumLockList *pVMMALockList = NULL;
+ ComPtr<IToken> pHDLockToken;
ComObjPtr<MediumAttachment> pOnlineMediumAttachment;
if (fOnlineMergePossible)
{
@@ -2408,9 +2498,10 @@ void SessionMachine::deleteSnapshotHandler(DeleteSnapshotTask &aTask)
fOnlineMergePossible,
pVMMALockList, pSource, pTarget,
fMergeForward, pParentForTarget,
- childrenToReparent,
+ pChildrenToReparent,
fNeedsOnlineMerge,
- pMediumLockList);
+ pMediumLockList,
+ pHDLockToken);
treeLock.acquire();
if (FAILED(rc))
throw rc;
@@ -2433,7 +2524,6 @@ void SessionMachine::deleteSnapshotHandler(DeleteSnapshotTask &aTask)
// then do a backward merge, i.e. merge its only child onto the
// base disk. Here we need then to update the attachment that
// refers to the child and have it point to the parent instead
- Assert(pHD->getParent().isNull());
Assert(pHD->getChildren().size() == 1);
ComObjPtr<Medium> pReplaceHD = pHD->getChildren().front();
@@ -2454,7 +2544,7 @@ void SessionMachine::deleteSnapshotHandler(DeleteSnapshotTask &aTask)
if (pSnapshotId)
replaceSnapshotId = *pSnapshotId;
- if (!replaceMachineId.isEmpty())
+ if (replaceMachineId.isValid() && !replaceMachineId.isZero())
{
// Adjust the backreferences, otherwise merging will assert.
// Note that the medium attachment object stays associated
@@ -2467,9 +2557,10 @@ void SessionMachine::deleteSnapshotHandler(DeleteSnapshotTask &aTask)
pOnlineMediumAttachment,
fMergeForward,
pParentForTarget,
- childrenToReparent,
+ pChildrenToReparent,
fNeedsOnlineMerge,
pMediumLockList,
+ pHDLockToken,
replaceMachineId,
replaceSnapshotId));
}
@@ -2478,9 +2569,116 @@ void SessionMachine::deleteSnapshotHandler(DeleteSnapshotTask &aTask)
pOnlineMediumAttachment,
fMergeForward,
pParentForTarget,
- childrenToReparent,
+ pChildrenToReparent,
fNeedsOnlineMerge,
- pMediumLockList));
+ pMediumLockList,
+ pHDLockToken));
+ }
+
+ {
+ /*check available place on the storage*/
+ RTFOFF pcbTotal = 0;
+ RTFOFF pcbFree = 0;
+ uint32_t pcbBlock = 0;
+ uint32_t pcbSector = 0;
+ std::multimap<uint32_t,uint64_t> neededStorageFreeSpace;
+ std::map<uint32_t,const char*> serialMapToStoragePath;
+
+ MediumDeleteRecList::const_iterator it_md = toDelete.begin();
+
+ while (it_md != toDelete.end())
+ {
+ uint64_t diskSize = 0;
+ uint32_t pu32Serial = 0;
+ ComObjPtr<Medium> pSource_local = it_md->mpSource;
+ ComObjPtr<Medium> pTarget_local = it_md->mpTarget;
+ ComPtr<IMediumFormat> pTargetFormat;
+
+ {
+ if ( pSource_local.isNull()
+ || pSource_local == pTarget_local)
+ {
+ ++it_md;
+ continue;
+ }
+ }
+
+ rc = pTarget_local->COMGETTER(MediumFormat)(pTargetFormat.asOutParam());
+ if (FAILED(rc))
+ throw rc;
+
+ if(pTarget_local->isMediumFormatFile())
+ {
+ int vrc = RTFsQuerySerial(pTarget_local->getLocationFull().c_str(), &pu32Serial);
+ if (RT_FAILURE(vrc))
+ {
+ rc = setError(E_FAIL,
+ tr(" Unable to merge storage '%s'. Can't get storage UID "),
+ pTarget_local->getLocationFull().c_str());
+ throw rc;
+ }
+
+ pSource_local->COMGETTER(Size)((LONG64*)&diskSize);
+
+ /* store needed free space in multimap */
+ neededStorageFreeSpace.insert(std::make_pair(pu32Serial,diskSize));
+ /* linking storage UID with snapshot path, it is a helper container (just for easy finding needed path) */
+ serialMapToStoragePath.insert(std::make_pair(pu32Serial,pTarget_local->getLocationFull().c_str()));
+ }
+
+ ++it_md;
+ }
+
+ while (!neededStorageFreeSpace.empty())
+ {
+ std::pair<std::multimap<uint32_t,uint64_t>::iterator,std::multimap<uint32_t,uint64_t>::iterator> ret;
+ uint64_t commonSourceStoragesSize = 0;
+
+ /* find all records in multimap with identical storage UID*/
+ ret = neededStorageFreeSpace.equal_range(neededStorageFreeSpace.begin()->first);
+ std::multimap<uint32_t,uint64_t>::const_iterator it_ns = ret.first;
+
+ for (; it_ns != ret.second ; ++it_ns)
+ {
+ commonSourceStoragesSize += it_ns->second;
+ }
+
+ /* find appropriate path by storage UID*/
+ std::map<uint32_t,const char*>::const_iterator it_sm = serialMapToStoragePath.find(ret.first->first);
+ /* get info about a storage */
+ if (it_sm == serialMapToStoragePath.end())
+ {
+ LogFlowThisFunc((" Path to the storage wasn't found...\n "));
+
+ rc = setError(E_INVALIDARG,
+ tr(" Unable to merge storage '%s'. Path to the storage wasn't found. "),
+ it_sm->second);
+ throw rc;
+ }
+
+ int vrc = RTFsQuerySizes(it_sm->second, &pcbTotal, &pcbFree,&pcbBlock, &pcbSector);
+ if (RT_FAILURE(vrc))
+ {
+ rc = setError(E_FAIL,
+ tr(" Unable to merge storage '%s'. Can't get the storage size. "),
+ it_sm->second);
+ throw rc;
+ }
+
+ if (commonSourceStoragesSize > (uint64_t)pcbFree)
+ {
+ LogFlowThisFunc((" Not enough free space to merge...\n "));
+
+ rc = setError(E_OUTOFMEMORY,
+ tr(" Unable to merge storage '%s' - not enough free storage space. "),
+ it_sm->second);
+ throw rc;
+ }
+
+ neededStorageFreeSpace.erase(ret.first, ret.second);
+ }
+
+ serialMapToStoragePath.clear();
}
// we can release the locks now since the machine state is MachineState_DeletingSnapshot
@@ -2572,16 +2770,22 @@ void SessionMachine::deleteSnapshotHandler(DeleteSnapshotTask &aTask)
bool fNeedsSave = false;
if (it->mfNeedsOnlineMerge)
{
+ // Put the medium merge information (MediumDeleteRec) where
+ // SessionMachine::FinishOnlineMergeMedium can get at it.
+ // This callback will arrive while onlineMergeMedium is
+ // still executing, and there can't be two tasks.
+ mConsoleTaskData.mDeleteSnapshotInfo = (void *)&(*it);
// online medium merge, in the direction decided earlier
rc = onlineMergeMedium(it->mpOnlineMediumAttachment,
it->mpSource,
it->mpTarget,
it->mfMergeForward,
it->mpParentForTarget,
- it->mChildrenToReparent,
+ it->mpChildrenToReparent,
it->mpMediumLockList,
aTask.pProgress,
&fNeedsSave);
+ mConsoleTaskData.mDeleteSnapshotInfo = NULL;
}
else
{
@@ -2589,7 +2793,7 @@ void SessionMachine::deleteSnapshotHandler(DeleteSnapshotTask &aTask)
rc = it->mpSource->mergeTo(it->mpTarget,
it->mfMergeForward,
it->mpParentForTarget,
- it->mChildrenToReparent,
+ it->mpChildrenToReparent,
it->mpMediumLockList,
&aTask.pProgress,
true /* aWait */);
@@ -2708,7 +2912,9 @@ void SessionMachine::deleteSnapshotHandler(DeleteSnapshotTask &aTask)
mParent->markRegistryModified(getId());
}
}
- catch (HRESULT aRC) { rc = aRC; }
+ catch (HRESULT aRC) {
+ rc = aRC;
+ }
if (FAILED(rc))
{
@@ -2726,10 +2932,10 @@ void SessionMachine::deleteSnapshotHandler(DeleteSnapshotTask &aTask)
++it)
{
cancelDeleteSnapshotMedium(it->mpHD, it->mpSource,
- it->mChildrenToReparent,
+ it->mpChildrenToReparent,
it->mfNeedsOnlineMerge,
- it->mpMediumLockList, it->mMachineId,
- it->mSnapshotId);
+ it->mpMediumLockList, it->mpHDLockToken,
+ it->mMachineId, it->mSnapshotId);
}
}
@@ -2780,14 +2986,16 @@ void SessionMachine::deleteSnapshotHandler(DeleteSnapshotTask &aTask)
* @param aTarget Target hard disk for merge (out).
* @param aMergeForward Merge direction decision (out).
* @param aParentForTarget New parent if target needs to be reparented (out).
- * @param aChildrenToReparent Children which have to be reparented to the
- * target (out).
+ * @param aChildrenToReparent MediumLockList with children which have to be
+ * reparented to the target (out).
* @param fNeedsOnlineMerge Whether this merge needs to be done online (out).
* If this is set to @a true then the @a aVMMALockList
* parameter has been modified and is returned as
* @a aMediumLockList.
* @param aMediumLockList Where to store the created medium lock list (may
* return NULL if no real merge is necessary).
+ * @param aHDLockToken Where to store the write lock token for aHD, in case
+ * it is not merged or deleted (out).
*
* @note Caller must hold media tree lock for writing. This locks this object
* and every medium object on the merge chain for writing.
@@ -2801,9 +3009,10 @@ HRESULT SessionMachine::prepareDeleteSnapshotMedium(const ComObjPtr<Medium> &aHD
ComObjPtr<Medium> &aTarget,
bool &aMergeForward,
ComObjPtr<Medium> &aParentForTarget,
- MediaList &aChildrenToReparent,
+ MediumLockList * &aChildrenToReparent,
bool &fNeedsOnlineMerge,
- MediumLockList * &aMediumLockList)
+ MediumLockList * &aMediumLockList,
+ ComPtr<IToken> &aHDLockToken)
{
Assert(!mParent->getMediaTreeLockHandle().isWriteLockOnCurrentThread());
Assert(!fOnlineMergePossible || VALID_PTR(aVMMALockList));
@@ -2816,6 +3025,7 @@ HRESULT SessionMachine::prepareDeleteSnapshotMedium(const ComObjPtr<Medium> &aHD
&& type != MediumType_Shareable
&& type != MediumType_Readonly, E_FAIL);
+ aChildrenToReparent = NULL;
aMediumLockList = NULL;
fNeedsOnlineMerge = false;
@@ -2832,7 +3042,7 @@ HRESULT SessionMachine::prepareDeleteSnapshotMedium(const ComObjPtr<Medium> &aHD
/* lock only, to prevent any usage until the snapshot deletion
* is completed */
alock.release();
- return aHD->LockWrite(NULL);
+ return aHD->LockWrite(aHDLockToken.asOutParam());
}
/* the differencing hard disk w/o children will be deleted, protect it
@@ -2863,7 +3073,7 @@ HRESULT SessionMachine::prepareDeleteSnapshotMedium(const ComObjPtr<Medium> &aHD
* deletion, so lock only, to prevent any usage */
childLock.release();
alock.release();
- return aHD->LockWrite(NULL);
+ return aHD->LockWrite(aHDLockToken.asOutParam());
}
aSource = pChild;
@@ -2871,9 +3081,30 @@ HRESULT SessionMachine::prepareDeleteSnapshotMedium(const ComObjPtr<Medium> &aHD
}
else
{
- /* forward merge */
- aSource = aHD;
- aTarget = pChild;
+ /* Determine best merge direction. */
+ bool fMergeForward = true;
+
+ childLock.release();
+ alock.release();
+ HRESULT rc = aHD->queryPreferredMergeDirection(pChild, fMergeForward);
+ alock.acquire();
+ childLock.acquire();
+
+ if (FAILED(rc) && rc != E_FAIL)
+ return rc;
+
+ if (fMergeForward)
+ {
+ aSource = aHD;
+ aTarget = pChild;
+ LogFlowFunc(("Forward merging selected\n"));
+ }
+ else
+ {
+ aSource = pChild;
+ aTarget = aHD;
+ LogFlowFunc(("Backward merging selected\n"));
+ }
}
HRESULT rc;
@@ -2939,39 +3170,37 @@ HRESULT SessionMachine::prepareDeleteSnapshotMedium(const ComObjPtr<Medium> &aHD
if (fOnlineMergePossible)
{
/* we will lock the children of the source for reparenting */
- for (MediaList::const_iterator it = aChildrenToReparent.begin();
- it != aChildrenToReparent.end();
- ++it)
+ if (aChildrenToReparent && !aChildrenToReparent->IsEmpty())
{
- ComObjPtr<Medium> pMedium = *it;
- AutoReadLock mediumLock(pMedium COMMA_LOCKVAL_SRC_POS);
- if (pMedium->getState() == MediumState_Created)
- {
- mediumLock.release();
- childLock.release();
- alock.release();
- rc = pMedium->LockWrite(NULL);
- alock.acquire();
- childLock.acquire();
- mediumLock.acquire();
- if (FAILED(rc))
- throw rc;
- }
- else
+ /* Cannot just call aChildrenToReparent->Lock(), as one of
+ * the children is the one under which the current state of
+ * the VM is located, and this means it is already locked
+ * (for reading). Note that no special unlocking is needed,
+ * because cancelMergeTo will unlock everything locked in
+ * its context (using the unlock on destruction), and both
+ * cancelDeleteSnapshotMedium (in case something fails) and
+ * FinishOnlineMergeMedium re-define the read/write lock
+ * state of everything which the VM need, search for the
+ * UpdateLock method calls. */
+ childLock.release();
+ alock.release();
+ rc = aChildrenToReparent->Lock(true /* fSkipOverLockedMedia */);
+ alock.acquire();
+ childLock.acquire();
+ MediumLockList::Base::iterator childrenToReparentBegin = aChildrenToReparent->GetBegin();
+ MediumLockList::Base::iterator childrenToReparentEnd = aChildrenToReparent->GetEnd();
+ for (MediumLockList::Base::iterator it = childrenToReparentBegin;
+ it != childrenToReparentEnd;
+ ++it)
{
- mediumLock.release();
- childLock.release();
- alock.release();
- rc = aVMMALockList->Update(pMedium, true);
- alock.acquire();
- childLock.acquire();
- mediumLock.acquire();
- if (FAILED(rc))
+ ComObjPtr<Medium> pMedium = it->GetMedium();
+ AutoReadLock mediumLock(pMedium COMMA_LOCKVAL_SRC_POS);
+ if (!it->IsLocked())
{
mediumLock.release();
childLock.release();
alock.release();
- rc = pMedium->LockWrite(NULL);
+ rc = aVMMALockList->Update(pMedium, true);
alock.acquire();
childLock.acquire();
mediumLock.acquire();
@@ -3058,6 +3287,7 @@ HRESULT SessionMachine::prepareDeleteSnapshotMedium(const ComObjPtr<Medium> &aHD
* @param aChildrenToReparent Children to unlock.
* @param fNeedsOnlineMerge Whether this merge needs to be done online.
* @param aMediumLockList Medium locks to cancel.
+ * @param aHDLockToken Optional write lock token for aHD.
* @param aMachineId Machine id to attach the medium to.
* @param aSnapshotId Snapshot id to attach the medium to.
*
@@ -3065,9 +3295,10 @@ HRESULT SessionMachine::prepareDeleteSnapshotMedium(const ComObjPtr<Medium> &aHD
*/
void SessionMachine::cancelDeleteSnapshotMedium(const ComObjPtr<Medium> &aHD,
const ComObjPtr<Medium> &aSource,
- const MediaList &aChildrenToReparent,
+ MediumLockList *aChildrenToReparent,
bool fNeedsOnlineMerge,
MediumLockList *aMediumLockList,
+ const ComPtr<IToken> &aHDLockToken,
const Guid &aMachineId,
const Guid &aSnapshotId)
{
@@ -3079,8 +3310,12 @@ void SessionMachine::cancelDeleteSnapshotMedium(const ComObjPtr<Medium> &aHD,
if (aHD->getParent().isNull())
{
- HRESULT rc = aHD->UnlockWrite(NULL);
- AssertComRC(rc);
+ Assert(!aHDLockToken.isNull());
+ if (!aHDLockToken.isNull())
+ {
+ HRESULT rc = aHDLockToken->Abandon();
+ AssertComRC(rc);
+ }
}
else
{
@@ -3128,7 +3363,7 @@ void SessionMachine::cancelDeleteSnapshotMedium(const ComObjPtr<Medium> &aHD,
}
}
- if (!aMachineId.isEmpty())
+ if (aMachineId.isValid() && !aMachineId.isZero())
{
// reattach the source media to the snapshot
HRESULT rc = aSource->addBackReference(aMachineId, aSnapshotId);
@@ -3147,8 +3382,8 @@ void SessionMachine::cancelDeleteSnapshotMedium(const ComObjPtr<Medium> &aHD,
* @param aTarget Target hard disk for merge.
* @param aMergeForward Merge direction.
* @param aParentForTarget New parent if target needs to be reparented.
- * @param aChildrenToReparent Children which have to be reparented to the
- * target.
+ * @param aChildrenToReparent Medium lock list with children which have to be
+ * reparented to the target.
* @param aMediumLockList Where to store the created medium lock list (may
* return NULL if no real merge is necessary).
* @param aProgress Progress indicator.
@@ -3159,7 +3394,7 @@ HRESULT SessionMachine::onlineMergeMedium(const ComObjPtr<MediumAttachment> &aMe
const ComObjPtr<Medium> &aTarget,
bool fMergeForward,
const ComObjPtr<Medium> &aParentForTarget,
- const MediaList &aChildrenToReparent,
+ MediumLockList *aChildrenToReparent,
MediumLockList *aMediumLockList,
ComObjPtr<Progress> &aProgress,
bool *pfNeedsMachineSaveSettings)
@@ -3168,6 +3403,9 @@ HRESULT SessionMachine::onlineMergeMedium(const ComObjPtr<MediumAttachment> &aMe
AssertReturn(aTarget != NULL, E_FAIL);
AssertReturn(aSource != aTarget, E_FAIL);
AssertReturn(aMediumLockList != NULL, E_FAIL);
+ NOREF(fMergeForward);
+ NOREF(aParentForTarget);
+ NOREF(aChildrenToReparent);
HRESULT rc = S_OK;
@@ -3208,12 +3446,6 @@ HRESULT SessionMachine::onlineMergeMedium(const ComObjPtr<MediumAttachment> &aMe
ComAssertThrow( uSourceIdx != (unsigned)-1
&& uTargetIdx != (unsigned)-1, E_FAIL);
- // For forward merges, tell the VM what images need to have their
- // parent UUID updated. This cannot be done in VBoxSVC, as opening
- // the required parent images is not safe while the VM is running.
- // For backward merges this will be simply an array of size 0.
- com::SafeIfaceArray<IMedium> childrenToReparent(aChildrenToReparent);
-
ComPtr<IInternalSessionControl> directControl;
{
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
@@ -3229,9 +3461,6 @@ HRESULT SessionMachine::onlineMergeMedium(const ComObjPtr<MediumAttachment> &aMe
// updating the medium attachment, chain linking and state.
rc = directControl->OnlineMergeMedium(aMediumAttachment,
uSourceIdx, uTargetIdx,
- aSource, aTarget,
- fMergeForward, aParentForTarget,
- ComSafeArrayAsInParam(childrenToReparent),
aProgress);
if (FAILED(rc))
throw rc;
@@ -3247,7 +3476,7 @@ HRESULT SessionMachine::onlineMergeMedium(const ComObjPtr<MediumAttachment> &aMe
}
/**
- * Implementation for IInternalMachineControl::finishOnlineMergeMedium().
+ * Implementation for IInternalMachineControl::FinishOnlineMergeMedium().
*
* Gets called after the successful completion of an online merge from
* Console::onlineMergeMedium(), which gets invoked indirectly above in
@@ -3256,17 +3485,11 @@ HRESULT SessionMachine::onlineMergeMedium(const ComObjPtr<MediumAttachment> &aMe
* This updates the medium information and medium state so that the VM
* can continue with the updated state of the medium chain.
*/
-STDMETHODIMP SessionMachine::FinishOnlineMergeMedium(IMediumAttachment *aMediumAttachment,
- IMedium *aSource,
- IMedium *aTarget,
- BOOL aMergeForward,
- IMedium *aParentForTarget,
- ComSafeArrayIn(IMedium *, aChildrenToReparent))
+STDMETHODIMP SessionMachine::FinishOnlineMergeMedium()
{
HRESULT rc = S_OK;
- ComObjPtr<Medium> pSource(static_cast<Medium *>(aSource));
- ComObjPtr<Medium> pTarget(static_cast<Medium *>(aTarget));
- ComObjPtr<Medium> pParentForTarget(static_cast<Medium *>(aParentForTarget));
+ MediumDeleteRec *pDeleteRec = (MediumDeleteRec *)mConsoleTaskData.mDeleteSnapshotInfo;
+ AssertReturn(pDeleteRec, E_FAIL);
bool fSourceHasChildren = false;
// all hard disks but the target were successfully deleted by
@@ -3279,36 +3502,35 @@ STDMETHODIMP SessionMachine::FinishOnlineMergeMedium(IMediumAttachment *aMediumA
// we delete the last reference to the no longer existing medium object.
ComObjPtr<Medium> targetChild;
- if (aMergeForward)
+ if (pDeleteRec->mfMergeForward)
{
// first, unregister the target since it may become a base
// hard disk which needs re-registration
- rc = mParent->unregisterMedium(pTarget);
+ rc = mParent->unregisterMedium(pDeleteRec->mpTarget);
AssertComRC(rc);
// then, reparent it and disconnect the deleted branch at
// both ends (chain->parent() is source's parent)
- pTarget->deparent();
- pTarget->setParent(pParentForTarget);
- if (pParentForTarget)
- pSource->deparent();
+ pDeleteRec->mpTarget->deparent();
+ pDeleteRec->mpTarget->setParent(pDeleteRec->mpParentForTarget);
+ if (pDeleteRec->mpParentForTarget)
+ pDeleteRec->mpSource->deparent();
// then, register again
- rc = mParent->registerMedium(pTarget, &pTarget, DeviceType_HardDisk);
+ rc = mParent->registerMedium(pDeleteRec->mpTarget, &pDeleteRec->mpTarget, DeviceType_HardDisk);
AssertComRC(rc);
}
else
{
- Assert(pTarget->getChildren().size() == 1);
- targetChild = pTarget->getChildren().front();
+ Assert(pDeleteRec->mpTarget->getChildren().size() == 1);
+ targetChild = pDeleteRec->mpTarget->getChildren().front();
// disconnect the deleted branch at the elder end
targetChild->deparent();
// Update parent UUIDs of the source's children, reparent them and
// disconnect the deleted branch at the younger end
- com::SafeIfaceArray<IMedium> childrenToReparent(ComSafeArrayInArg(aChildrenToReparent));
- if (childrenToReparent.size() > 0)
+ if (pDeleteRec->mpChildrenToReparent && !pDeleteRec->mpChildrenToReparent->IsEmpty())
{
fSourceHasChildren = true;
// Fix the parent UUID of the images which needs to be moved to
@@ -3316,35 +3538,35 @@ STDMETHODIMP SessionMachine::FinishOnlineMergeMedium(IMediumAttachment *aMediumA
// but only for reading since the VM is paused. If anything fails
// we must continue. The worst possible result is that the images
// need manual fixing via VBoxManage to adjust the parent UUID.
- MediaList toReparent;
- for (size_t i = 0; i < childrenToReparent.size(); i++)
- {
- Medium *pMedium = static_cast<Medium *>(childrenToReparent[i]);
- toReparent.push_back(pMedium);
- }
treeLock.release();
- pTarget->fixParentUuidOfChildren(toReparent);
+ pDeleteRec->mpTarget->fixParentUuidOfChildren(pDeleteRec->mpChildrenToReparent);
+ // The childen are still write locked, unlock them now and don't
+ // rely on the destructor doing it very late.
+ pDeleteRec->mpChildrenToReparent->Unlock();
treeLock.acquire();
// obey {parent,child} lock order
- AutoWriteLock sourceLock(pSource COMMA_LOCKVAL_SRC_POS);
+ AutoWriteLock sourceLock(pDeleteRec->mpSource COMMA_LOCKVAL_SRC_POS);
- for (size_t i = 0; i < childrenToReparent.size(); i++)
+ MediumLockList::Base::iterator childrenBegin = pDeleteRec->mpChildrenToReparent->GetBegin();
+ MediumLockList::Base::iterator childrenEnd = pDeleteRec->mpChildrenToReparent->GetEnd();
+ for (MediumLockList::Base::iterator it = childrenBegin;
+ it != childrenEnd;
+ ++it)
{
- Medium *pMedium = static_cast<Medium *>(childrenToReparent[i]);
+ Medium *pMedium = it->GetMedium();
AutoWriteLock childLock(pMedium COMMA_LOCKVAL_SRC_POS);
pMedium->deparent(); // removes pMedium from source
- pMedium->setParent(pTarget);
+ pMedium->setParent(pDeleteRec->mpTarget);
}
}
}
/* unregister and uninitialize all hard disks removed by the merge */
MediumLockList *pMediumLockList = NULL;
- MediumAttachment *pMediumAttachment = static_cast<MediumAttachment *>(aMediumAttachment);
- rc = mData->mSession.mLockedMedia.Get(pMediumAttachment, pMediumLockList);
- const ComObjPtr<Medium> &pLast = aMergeForward ? pTarget : pSource;
+ rc = mData->mSession.mLockedMedia.Get(pDeleteRec->mpOnlineMediumAttachment, pMediumLockList);
+ const ComObjPtr<Medium> &pLast = pDeleteRec->mfMergeForward ? pDeleteRec->mpTarget : pDeleteRec->mpSource;
AssertReturn(SUCCEEDED(rc) && pMediumLockList, E_FAIL);
MediumLockList::Base::iterator lockListBegin =
pMediumLockList->GetBegin();
@@ -3360,7 +3582,7 @@ STDMETHODIMP SessionMachine::FinishOnlineMergeMedium(IMediumAttachment *aMediumA
const ComObjPtr<Medium> pMedium = mediumLock.GetMedium();
/* The target and all images not merged (readonly) are skipped */
- if ( pMedium == pTarget
+ if ( pMedium == pDeleteRec->mpTarget
|| pMedium->getState() == MediumState_LockedRead)
{
++it;
@@ -3382,10 +3604,10 @@ STDMETHODIMP SessionMachine::FinishOnlineMergeMedium(IMediumAttachment *aMediumA
* caller may still hold an AutoCaller instance for it
* and therefore we cannot uninit() it (it's therefore
* the caller's responsibility) */
- if (pMedium == aSource)
+ if (pMedium == pDeleteRec->mpSource)
{
- Assert(pSource->getChildren().size() == 0);
- Assert(pSource->getFirstMachineBackrefId() == NULL);
+ Assert(pDeleteRec->mpSource->getChildren().size() == 0);
+ Assert(pDeleteRec->mpSource->getFirstMachineBackrefId() == NULL);
}
/* Delete the medium lock list entry, which also releases the
@@ -3421,11 +3643,12 @@ STDMETHODIMP SessionMachine::FinishOnlineMergeMedium(IMediumAttachment *aMediumA
* source has no children) then update the medium associated with the
* attachment, as the previously associated one (source) is now deleted.
* Without the immediate update the VM could not continue running. */
- if (!aMergeForward && !fSourceHasChildren)
+ if (!pDeleteRec->mfMergeForward && !fSourceHasChildren)
{
- AutoWriteLock attLock(pMediumAttachment COMMA_LOCKVAL_SRC_POS);
- pMediumAttachment->updateMedium(pTarget);
+ AutoWriteLock attLock(pDeleteRec->mpOnlineMediumAttachment COMMA_LOCKVAL_SRC_POS);
+ pDeleteRec->mpOnlineMediumAttachment->updateMedium(pDeleteRec->mpTarget);
}
return S_OK;
}
+
diff --git a/src/VBox/Main/src-server/StorageControllerImpl.cpp b/src/VBox/Main/src-server/StorageControllerImpl.cpp
index 100c5b22..b5686933 100644
--- a/src/VBox/Main/src-server/StorageControllerImpl.cpp
+++ b/src/VBox/Main/src-server/StorageControllerImpl.cpp
@@ -6,7 +6,7 @@
*/
/*
- * Copyright (C) 2008-2010 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Main/src-server/SystemPropertiesImpl.cpp b/src/VBox/Main/src-server/SystemPropertiesImpl.cpp
index 380f7574..3e0ff614 100644
--- a/src/VBox/Main/src-server/SystemPropertiesImpl.cpp
+++ b/src/VBox/Main/src-server/SystemPropertiesImpl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -90,6 +90,7 @@ HRESULT SystemProperties::init(VirtualBox *aParent)
unconst(mParent) = aParent;
setDefaultMachineFolder(Utf8Str::Empty);
+ setLoggingLevel(Utf8Str::Empty);
setDefaultHardDiskFormat(Utf8Str::Empty);
setVRDEAuthLibrary(Utf8Str::Empty);
@@ -97,6 +98,18 @@ HRESULT SystemProperties::init(VirtualBox *aParent)
m->ulLogHistoryCount = 3;
+
+ /* On Windows and OS X, HW virtualization use isn't exclusive by
+ * default so that VT-x or AMD-V can be shared with other
+ * hypervisors without requiring user intervention.
+ * NB: See also SystemProperties constructor in settings.h
+ */
+#if defined(RT_OS_DARWIN) || defined(RT_OS_WINDOWS)
+ m->fExclusiveHwVirt = false;
+#else
+ m->fExclusiveHwVirt = true;
+#endif
+
HRESULT rc = S_OK;
/* Fetch info of all available hd backends. */
@@ -313,6 +326,36 @@ STDMETHODIMP SystemProperties::COMGETTER(MaxBootPosition)(ULONG *aMaxBootPositio
}
+STDMETHODIMP SystemProperties::COMGETTER(ExclusiveHwVirt)(BOOL *aExclusiveHwVirt)
+{
+ CheckComArgOutPointerValid(aExclusiveHwVirt);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ *aExclusiveHwVirt = m->fExclusiveHwVirt;
+
+ return S_OK;
+}
+
+STDMETHODIMP SystemProperties::COMSETTER(ExclusiveHwVirt)(BOOL aExclusiveHwVirt)
+{
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+ m->fExclusiveHwVirt = !!aExclusiveHwVirt;
+ alock.release();
+
+ // VirtualBox::saveSettings() needs vbox write lock
+ AutoWriteLock vboxLock(mParent COMMA_LOCKVAL_SRC_POS);
+ HRESULT rc = mParent->saveSettings();
+
+ return rc;
+}
+
STDMETHODIMP SystemProperties::GetMaxNetworkAdapters(ChipsetType_T aChipset, ULONG *count)
{
CheckComArgOutPointerValid(count);
@@ -346,6 +389,7 @@ STDMETHODIMP SystemProperties::GetMaxNetworkAdaptersOfType(ChipsetType_T aChipse
{
case NetworkAttachmentType_NAT:
case NetworkAttachmentType_Internal:
+ case NetworkAttachmentType_NATNetwork:
/* chipset default is OK */
break;
case NetworkAttachmentType_Bridged:
@@ -531,6 +575,8 @@ STDMETHODIMP SystemProperties::GetDeviceTypesForStorageBus(StorageBus_T aBus,
{
case StorageBus_IDE:
case StorageBus_SATA:
+ case StorageBus_SCSI:
+ case StorageBus_SAS:
{
com::SafeArray<DeviceType_T> saDeviceTypes(2);
saDeviceTypes[0] = DeviceType_DVD;
@@ -538,14 +584,6 @@ STDMETHODIMP SystemProperties::GetDeviceTypesForStorageBus(StorageBus_T aBus,
saDeviceTypes.detachTo(ComSafeArrayOutArg(aDeviceTypes));
break;
}
- case StorageBus_SCSI:
- case StorageBus_SAS:
- {
- com::SafeArray<DeviceType_T> saDeviceTypes(1);
- saDeviceTypes[0] = DeviceType_HardDisk;
- saDeviceTypes.detachTo(ComSafeArrayOutArg(aDeviceTypes));
- break;
- }
case StorageBus_Floppy:
{
com::SafeArray<DeviceType_T> saDeviceTypes(1);
@@ -588,6 +626,36 @@ STDMETHODIMP SystemProperties::GetDefaultIoCacheSettingForStorageController(Stor
return S_OK;
}
+STDMETHODIMP SystemProperties::GetMaxInstancesOfUSBControllerType(ChipsetType_T aChipset,
+ USBControllerType_T aType,
+ ULONG *aMaxInstances)
+{
+ NOREF(aChipset);
+ CheckComArgOutPointerValid(aMaxInstances);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ ULONG cCtrs = 0;
+
+ /* no need to lock, this is const */
+ switch (aType)
+ {
+ case USBControllerType_OHCI:
+ case USBControllerType_EHCI:
+ {
+ cCtrs = 1;
+ break;
+ }
+ default:
+ AssertMsgFailed(("Invalid bus type %d\n", aType));
+ }
+
+ *aMaxInstances = cCtrs;
+
+ return S_OK;
+}
+
STDMETHODIMP SystemProperties::COMGETTER(DefaultMachineFolder)(BSTR *aDefaultMachineFolder)
{
CheckComArgOutPointerValid(aDefaultMachineFolder);
@@ -621,6 +689,44 @@ STDMETHODIMP SystemProperties::COMSETTER(DefaultMachineFolder)(IN_BSTR aDefaultM
return rc;
}
+STDMETHODIMP SystemProperties::COMGETTER(LoggingLevel)(BSTR *aLoggingLevel)
+{
+ CheckComArgOutPointerValid(aLoggingLevel);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ Utf8Str useLoggingLevel(m->strLoggingLevel);
+ if (useLoggingLevel.isEmpty())
+ useLoggingLevel = VBOXSVC_LOG_DEFAULT;
+
+ useLoggingLevel.cloneTo(aLoggingLevel);
+ return S_OK;
+}
+
+
+STDMETHODIMP SystemProperties::COMSETTER(LoggingLevel)(IN_BSTR aLoggingLevel)
+{
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+ HRESULT rc = setLoggingLevel(aLoggingLevel);
+ alock.release();
+
+ if (SUCCEEDED(rc))
+ {
+ AutoWriteLock vboxLock(mParent COMMA_LOCKVAL_SRC_POS);
+ rc = mParent->saveSettings();
+ }
+ else
+ LogRel(("Cannot set passed logging level=%ls, or the default one - Error=%Rhrc \n", aLoggingLevel, rc));
+
+ return rc;
+}
+
STDMETHODIMP SystemProperties::COMGETTER(MediumFormats)(ComSafeArrayOut(IMediumFormat *, aMediumFormats))
{
CheckComArgOutSafeArrayPointerValid(aMediumFormats);
@@ -997,6 +1103,40 @@ STDMETHODIMP SystemProperties::COMSETTER(DefaultAdditionsISO)(IN_BSTR aDefaultAd
return rc;
}
+STDMETHODIMP SystemProperties::COMGETTER(DefaultFrontend)(BSTR *aDefaultFrontend)
+{
+ CheckComArgOutPointerValid(aDefaultFrontend);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+ m->strDefaultFrontend.cloneTo(aDefaultFrontend);
+
+ return S_OK;
+}
+
+STDMETHODIMP SystemProperties::COMSETTER(DefaultFrontend)(IN_BSTR aDefaultFrontend)
+{
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+ if (m->strDefaultFrontend == Utf8Str(aDefaultFrontend))
+ return S_OK;
+ HRESULT rc = setDefaultFrontend(aDefaultFrontend);
+ alock.release();
+
+ if (SUCCEEDED(rc))
+ {
+ // VirtualBox::saveSettings() needs vbox write lock
+ AutoWriteLock vboxLock(mParent COMMA_LOCKVAL_SRC_POS);
+ rc = mParent->saveSettings();
+ }
+
+ return rc;
+}
+
// public methods only for internal purposes
/////////////////////////////////////////////////////////////////////////////
@@ -1012,6 +1152,9 @@ HRESULT SystemProperties::loadSettings(const settings::SystemProperties &data)
rc = setDefaultMachineFolder(data.strDefaultMachineFolder);
if (FAILED(rc)) return rc;
+ rc = setLoggingLevel(data.strLoggingLevel);
+ if (FAILED(rc)) return rc;
+
rc = setDefaultHardDiskFormat(data.strDefaultHardDiskFormat);
if (FAILED(rc)) return rc;
@@ -1025,6 +1168,7 @@ HRESULT SystemProperties::loadSettings(const settings::SystemProperties &data)
if (FAILED(rc)) return rc;
m->ulLogHistoryCount = data.ulLogHistoryCount;
+ m->fExclusiveHwVirt = data.fExclusiveHwVirt;
rc = setAutostartDatabasePath(data.strAutostartDatabasePath);
if (FAILED(rc)) return rc;
@@ -1036,6 +1180,9 @@ HRESULT SystemProperties::loadSettings(const settings::SystemProperties &data)
(void)setDefaultAdditionsISO(data.strDefaultAdditionsISO);
}
+ rc = setDefaultFrontend(data.strDefaultFrontend);
+ if (FAILED(rc)) return rc;
+
return S_OK;
}
@@ -1074,7 +1221,7 @@ ComObjPtr<MediumFormat> SystemProperties::mediumFormat(const Utf8Str &aFormat)
{
/* MediumFormat is all const, no need to lock */
- if ((*it)->getId().compare(aFormat, Utf8Str::CaseInsensitive) == 0)
+ if ((*it)->i_getId().compare(aFormat, Utf8Str::CaseInsensitive) == 0)
{
format = *it;
break;
@@ -1107,8 +1254,8 @@ ComObjPtr<MediumFormat> SystemProperties::mediumFormatFromExtension(const Utf8St
++it)
{
/* MediumFormat is all const, no need to lock */
- MediumFormat::StrList aFileList = (*it)->getFileExtensions();
- for (MediumFormat::StrList::const_iterator it1 = aFileList.begin();
+ MediumFormat::StrArray aFileList = (*it)->i_getFileExtensions();
+ for (MediumFormat::StrArray::const_iterator it1 = aFileList.begin();
it1 != aFileList.end();
++it1)
{
@@ -1177,6 +1324,31 @@ HRESULT SystemProperties::setDefaultMachineFolder(const Utf8Str &strPath)
return S_OK;
}
+HRESULT SystemProperties::setLoggingLevel(const Utf8Str &aLoggingLevel)
+{
+ Utf8Str useLoggingLevel(aLoggingLevel);
+ int rc = RTLogGroupSettings(RTLogRelDefaultInstance(), useLoggingLevel.c_str());
+ // If failed and not the default logging level - try to use the default logging level.
+ if (RT_FAILURE(rc))
+ {
+ // If failed write message to the release log.
+ LogRel(("Cannot set passed logging level=%s Error=%Rrc \n", useLoggingLevel.c_str(), rc));
+ // If attempted logging level not the default one then try the default one.
+ if (!useLoggingLevel.equals(VBOXSVC_LOG_DEFAULT))
+ {
+ rc = RTLogGroupSettings(RTLogRelDefaultInstance(), VBOXSVC_LOG_DEFAULT);
+ // If failed report this to the release log.
+ if (RT_FAILURE(rc))
+ LogRel(("Cannot set default logging level Error=%Rrc \n", rc));
+ }
+ // On any failure - set default level as the one to be stored.
+ useLoggingLevel = VBOXSVC_LOG_DEFAULT;
+ }
+ // Set to passed value or if default used/attempted (even if error condition) use empty string.
+ m->strLoggingLevel = (useLoggingLevel.equals(VBOXSVC_LOG_DEFAULT) ? "" : useLoggingLevel);
+ return RT_SUCCESS(rc) ? S_OK : E_FAIL;
+}
+
HRESULT SystemProperties::setDefaultHardDiskFormat(const Utf8Str &aFormat)
{
if (!aFormat.isEmpty())
@@ -1288,3 +1460,10 @@ HRESULT SystemProperties::setDefaultAdditionsISO(const Utf8Str &aPath)
return S_OK;
}
+
+HRESULT SystemProperties::setDefaultFrontend(const Utf8Str &aDefaultFrontend)
+{
+ m->strDefaultFrontend = aDefaultFrontend;
+
+ return S_OK;
+}
diff --git a/src/VBox/Main/src-server/TokenImpl.cpp b/src/VBox/Main/src-server/TokenImpl.cpp
new file mode 100644
index 00000000..29802e7b
--- /dev/null
+++ b/src/VBox/Main/src-server/TokenImpl.cpp
@@ -0,0 +1,217 @@
+/* $Id: TokenImpl.cpp $ */
+/** @file
+ *
+ * Token COM class implementation: MachineToken and MediumLockToken
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "TokenImpl.h"
+#include "MachineImpl.h"
+#include "MediumImpl.h"
+#include "AutoCaller.h"
+#include "Logging.h"
+
+// constructor / destructor
+/////////////////////////////////////////////////////////////////////////////
+
+DEFINE_EMPTY_CTOR_DTOR(MachineToken)
+
+HRESULT MachineToken::FinalConstruct()
+{
+ return BaseFinalConstruct();
+}
+
+void MachineToken::FinalRelease()
+{
+ uninit(false);
+
+ BaseFinalRelease();
+}
+
+// public initializer/uninitializer for internal purposes only
+/////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Initializes the token object.
+ *
+ * @param pSessionMachine Pointer to a SessionMachine object.
+ */
+HRESULT MachineToken::init(const ComObjPtr<SessionMachine> &pSessionMachine)
+{
+ LogFlowThisFunc(("pSessionMachine=%p\n", &pSessionMachine));
+
+ ComAssertRet(!pSessionMachine.isNull(), E_INVALIDARG);
+
+ /* Enclose the state transition NotReady->InInit->Ready */
+ AutoInitSpan autoInitSpan(this);
+ AssertReturn(autoInitSpan.isOk(), E_FAIL);
+
+ m.pSessionMachine = pSessionMachine;
+
+ /* Confirm a successful initialization */
+ autoInitSpan.setSucceeded();
+
+ return S_OK;
+}
+
+/**
+ * Uninitializes the instance and sets the ready flag to FALSE.
+ * Called either from FinalRelease() or by the parent when it gets destroyed.
+ */
+void MachineToken::uninit(bool fAbandon)
+{
+ LogFlowThisFunc(("\n"));
+
+ /* Enclose the state transition Ready->InUninit->NotReady */
+ AutoUninitSpan autoUninitSpan(this);
+ if (autoUninitSpan.uninitDone())
+ return;
+
+ /* Destroy the SessionMachine object, check is paranoia */
+ if (!m.pSessionMachine.isNull())
+ {
+ m.pSessionMachine->uninit(fAbandon ? SessionMachine::Uninit::Normal : SessionMachine::Uninit::Abnormal);
+ m.pSessionMachine.setNull();
+ }
+}
+
+// IToken methods
+/////////////////////////////////////////////////////////////////////////////
+
+HRESULT MachineToken::abandon(AutoCaller &aAutoCaller)
+{
+ /* have to release the AutoCaller before calling uninit(), self-deadlock */
+ aAutoCaller.release();
+
+ /* uninit does everything we need */
+ uninit(true);
+ return S_OK;
+}
+
+HRESULT MachineToken::dummy()
+{
+ /* Remember, the wrapper contains the AutoCaller, which means that after
+ * uninit() this code won't be reached any more. */
+
+ /* this is a NOOP, no need to lock */
+
+ return S_OK;
+}
+
+// public methods only for internal purposes
+/////////////////////////////////////////////////////////////////////////////
+
+
+// constructor / destructor
+/////////////////////////////////////////////////////////////////////////////
+
+DEFINE_EMPTY_CTOR_DTOR(MediumLockToken)
+
+HRESULT MediumLockToken::FinalConstruct()
+{
+ return BaseFinalConstruct();
+}
+
+void MediumLockToken::FinalRelease()
+{
+ uninit();
+
+ BaseFinalRelease();
+}
+
+// public initializer/uninitializer for internal purposes only
+/////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Initializes the token object.
+ *
+ * @param pMedium Pointer to a Medium object.
+ * @param fWrite True if this is a write lock, false otherwise.
+ */
+HRESULT MediumLockToken::init(const ComObjPtr<Medium> &pMedium, bool fWrite)
+{
+ LogFlowThisFunc(("pMedium=%p\n", &pMedium));
+
+ ComAssertRet(!pMedium.isNull(), E_INVALIDARG);
+
+ /* Enclose the state transition NotReady->InInit->Ready */
+ AutoInitSpan autoInitSpan(this);
+ AssertReturn(autoInitSpan.isOk(), E_FAIL);
+
+ m.pMedium = pMedium;
+ m.fWrite = fWrite;
+
+ /* Confirm a successful initialization */
+ autoInitSpan.setSucceeded();
+
+ return S_OK;
+}
+
+/**
+ * Uninitializes the instance and sets the ready flag to FALSE.
+ * Called either from FinalRelease() or by the parent when it gets destroyed.
+ */
+void MediumLockToken::uninit()
+{
+ LogFlowThisFunc(("\n"));
+
+ /* Enclose the state transition Ready->InUninit->NotReady */
+ AutoUninitSpan autoUninitSpan(this);
+ if (autoUninitSpan.uninitDone())
+ return;
+
+ /* Release the appropriate lock, check is paranoia */
+ if (!m.pMedium.isNull())
+ {
+ if (m.fWrite)
+ {
+ HRESULT rc = m.pMedium->unlockWrite(NULL);
+ AssertComRC(rc);
+ }
+ else
+ {
+ HRESULT rc = m.pMedium->unlockRead(NULL);
+ AssertComRC(rc);
+ }
+ m.pMedium.setNull();
+ }
+}
+
+// IToken methods
+/////////////////////////////////////////////////////////////////////////////
+
+HRESULT MediumLockToken::abandon(AutoCaller &aAutoCaller)
+{
+ /* have to release the AutoCaller before calling uninit(), self-deadlock */
+ aAutoCaller.release();
+
+ /* uninit does everything we need */
+ uninit();
+ return S_OK;
+}
+
+HRESULT MediumLockToken::dummy()
+{
+ /* Remember, the wrapper contains the AutoCaller, which means that after
+ * uninit() this code won't be reached any more. */
+
+ /* this is a NOOP, no need to lock */
+
+ return S_OK;
+}
+
+// public methods only for internal purposes
+/////////////////////////////////////////////////////////////////////////////
+
+/* vi: set tabstop=4 shiftwidth=4 expandtab: */
diff --git a/src/VBox/Main/src-server/USBControllerImpl.cpp b/src/VBox/Main/src-server/USBControllerImpl.cpp
index 8f4d1c48..18c4f43e 100644
--- a/src/VBox/Main/src-server/USBControllerImpl.cpp
+++ b/src/VBox/Main/src-server/USBControllerImpl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2005-2012 Oracle Corporation
+ * Copyright (C) 2005-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -21,18 +21,13 @@
#include "MachineImpl.h"
#include "VirtualBoxImpl.h"
#include "HostImpl.h"
-#ifdef VBOX_WITH_USB
-# include "USBDeviceImpl.h"
-# include "HostUSBDeviceImpl.h"
-# include "USBProxyService.h"
-# include "USBDeviceFilterImpl.h"
-#endif
#include <iprt/string.h>
#include <iprt/cpp/utils.h>
#include <VBox/err.h>
#include <VBox/settings.h>
+#include <VBox/com/array.h>
#include <algorithm>
@@ -43,41 +38,31 @@
// defines
/////////////////////////////////////////////////////////////////////////////
-typedef std::list< ComObjPtr<USBDeviceFilter> > DeviceFilterList;
-
struct BackupableUSBData
{
BackupableUSBData()
- : fEnabled(false),
- fEnabledEHCI(false)
+ : enmType(USBControllerType_Null)
{ }
- BOOL fEnabled;
- BOOL fEnabledEHCI;
+ Utf8Str strName;
+ USBControllerType_T enmType;
};
struct USBController::Data
{
Data(Machine *pMachine)
- : pParent(pMachine),
- pHost(pMachine->getVirtualBox()->host())
+ : pParent(pMachine)
{ }
~Data()
{};
Machine * const pParent;
- Host * const pHost;
// peer machine's USB controller
const ComObjPtr<USBController> pPeer;
Backupable<BackupableUSBData> bd;
-#ifdef VBOX_WITH_USB
- // the following fields need special backup/rollback/commit handling,
- // so they cannot be a part of BackupableData
- Backupable<DeviceFilterList> llDeviceFilters;
-#endif
};
@@ -106,12 +91,18 @@ void USBController::FinalRelease()
*
* @returns COM result indicator.
* @param aParent Pointer to our parent object.
+ * @param aName The name of the USB controller.
+ * @param enmType The USB controller type.
*/
-HRESULT USBController::init(Machine *aParent)
+HRESULT USBController::init(Machine *aParent, const Utf8Str &aName, USBControllerType_T enmType)
{
- LogFlowThisFunc(("aParent=%p\n", aParent));
+ LogFlowThisFunc(("aParent=%p aName=\"%s\"\n", aParent, aName.c_str()));
- ComAssertRet(aParent, E_INVALIDARG);
+ ComAssertRet(aParent && !aName.isEmpty(), E_INVALIDARG);
+ if ( (enmType <= USBControllerType_Null)
+ || (enmType > USBControllerType_EHCI))
+ return setError(E_INVALIDARG,
+ tr("Invalid USB controller type"));
/* Enclose the state transition NotReady->InInit->Ready */
AutoInitSpan autoInitSpan(this);
@@ -122,9 +113,8 @@ HRESULT USBController::init(Machine *aParent)
/* mPeer is left null */
m->bd.allocate();
-#ifdef VBOX_WITH_USB
- m->llDeviceFilters.allocate();
-#endif
+ m->bd->strName = aName;
+ m->bd->enmType = enmType;
/* Confirm a successful initialization */
autoInitSpan.setSucceeded();
@@ -140,13 +130,22 @@ HRESULT USBController::init(Machine *aParent)
* @returns COM result indicator.
* @param aParent Pointer to our parent object.
* @param aPeer The object to share.
+ * @param aReshare
+ * When false, the original object will remain a data owner.
+ * Otherwise, data ownership will be transferred from the original
+ * object to this one.
+ *
+ * @note This object must be destroyed before the original object
+ * it shares data with is destroyed.
*
- * @note This object must be destroyed before the original object
- * it shares data with is destroyed.
+ * @note Locks @a aThat object for writing if @a aReshare is @c true, or for
+ * reading if @a aReshare is false.
*/
-HRESULT USBController::init(Machine *aParent, USBController *aPeer)
+HRESULT USBController::init(Machine *aParent, USBController *aPeer,
+ bool fReshare /* = false */)
{
- LogFlowThisFunc(("aParent=%p, aPeer=%p\n", aParent, aPeer));
+ LogFlowThisFunc(("aParent=%p, aPeer=%p, fReshare=%RTbool\n",
+ aParent, aPeer, fReshare));
ComAssertRet(aParent && aPeer, E_INVALIDARG);
@@ -156,24 +155,24 @@ HRESULT USBController::init(Machine *aParent, USBController *aPeer)
m = new Data(aParent);
- unconst(m->pPeer) = aPeer;
+ /* sanity */
+ AutoCaller peerCaller(aPeer);
+ AssertComRCReturnRC(peerCaller.rc());
- AutoWriteLock thatlock(aPeer COMMA_LOCKVAL_SRC_POS);
- m->bd.share(aPeer->m->bd);
+ if (fReshare)
+ {
+ AutoWriteLock peerLock(aPeer COMMA_LOCKVAL_SRC_POS);
-#ifdef VBOX_WITH_USB
- /* create copies of all filters */
- m->llDeviceFilters.allocate();
- DeviceFilterList::const_iterator it = aPeer->m->llDeviceFilters->begin();
- while (it != aPeer->m->llDeviceFilters->end())
+ unconst(aPeer->m->pPeer) = this;
+ m->bd.attach (aPeer->m->bd);
+ }
+ else
{
- ComObjPtr<USBDeviceFilter> filter;
- filter.createObject();
- filter->init(this, *it);
- m->llDeviceFilters->push_back(filter);
- ++it;
+ unconst(m->pPeer) = aPeer;
+
+ AutoReadLock peerLock(aPeer COMMA_LOCKVAL_SRC_POS);
+ m->bd.share (aPeer->m->bd);
}
-#endif /* VBOX_WITH_USB */
/* Confirm a successful initialization */
autoInitSpan.setSucceeded();
@@ -204,20 +203,6 @@ HRESULT USBController::initCopy(Machine *aParent, USBController *aPeer)
AutoWriteLock thatlock(aPeer COMMA_LOCKVAL_SRC_POS);
m->bd.attachCopy(aPeer->m->bd);
-#ifdef VBOX_WITH_USB
- /* create private copies of all filters */
- m->llDeviceFilters.allocate();
- DeviceFilterList::const_iterator it = aPeer->m->llDeviceFilters->begin();
- while (it != aPeer->m->llDeviceFilters->end())
- {
- ComObjPtr<USBDeviceFilter> filter;
- filter.createObject();
- filter->initCopy(this, *it);
- m->llDeviceFilters->push_back(filter);
- ++it;
- }
-#endif /* VBOX_WITH_USB */
-
/* Confirm a successful initialization */
autoInitSpan.setSucceeded();
@@ -238,16 +223,6 @@ void USBController::uninit()
if (autoUninitSpan.uninitDone())
return;
-#ifdef VBOX_WITH_USB
- // uninit all device filters on the list (it's a standard std::list not an ObjectsList
- // so we must uninit() manually)
- for (DeviceFilterList::iterator it = m->llDeviceFilters->begin();
- it != m->llDeviceFilters->end();
- ++it)
- (*it)->uninit();
-
- m->llDeviceFilters.free();
-#endif
m->bd.free();
unconst(m->pPeer) = NULL;
@@ -260,112 +235,29 @@ void USBController::uninit()
// IUSBController properties
/////////////////////////////////////////////////////////////////////////////
-
-STDMETHODIMP USBController::COMGETTER(Enabled)(BOOL *aEnabled)
-{
- CheckComArgOutPointerValid(aEnabled);
-
- AutoCaller autoCaller(this);
- if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
- AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
- *aEnabled = m->bd->fEnabled;
-
- return S_OK;
-}
-
-
-STDMETHODIMP USBController::COMSETTER(Enabled)(BOOL aEnabled)
-{
- LogFlowThisFunc(("aEnabled=%RTbool\n", aEnabled));
-
- AutoCaller autoCaller(this);
- if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
- /* the machine needs to be mutable */
- AutoMutableStateDependency adep(m->pParent);
- if (FAILED(adep.rc())) return adep.rc();
-
- AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
- if (m->bd->fEnabled != aEnabled)
- {
- m->bd.backup();
- m->bd->fEnabled = aEnabled;
-
- // leave the lock for safety
- alock.release();
-
- AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS);
- m->pParent->setModified(Machine::IsModified_USB);
- mlock.release();
-
- m->pParent->onUSBControllerChange();
- }
-
- return S_OK;
-}
-
-STDMETHODIMP USBController::COMGETTER(EnabledEHCI)(BOOL *aEnabled)
-{
- CheckComArgOutPointerValid(aEnabled);
-
- AutoCaller autoCaller(this);
- if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
- AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
- *aEnabled = m->bd->fEnabledEHCI;
-
- return S_OK;
-}
-
-STDMETHODIMP USBController::COMSETTER(EnabledEHCI)(BOOL aEnabled)
+STDMETHODIMP USBController::COMGETTER(Name) (BSTR *aName)
{
- LogFlowThisFunc(("aEnabled=%RTbool\n", aEnabled));
+ CheckComArgOutPointerValid(aName);
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
- /* the machine needs to be mutable */
- AutoMutableStateDependency adep(m->pParent);
- if (FAILED(adep.rc())) return adep.rc();
-
- AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
- if (m->bd->fEnabledEHCI != aEnabled)
- {
- m->bd.backup();
- m->bd->fEnabledEHCI = aEnabled;
-
- // leave the lock for safety
- alock.release();
-
- AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS);
- m->pParent->setModified(Machine::IsModified_USB);
- mlock.release();
-
- m->pParent->onUSBControllerChange();
- }
+ /* strName is constant during life time, no need to lock */
+ m->bd->strName.cloneTo(aName);
return S_OK;
}
-STDMETHODIMP USBController::COMGETTER(ProxyAvailable)(BOOL *aEnabled)
+STDMETHODIMP USBController::COMGETTER(Type)(USBControllerType_T *aType)
{
- CheckComArgOutPointerValid(aEnabled);
+ CheckComArgOutPointerValid(aType);
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-#ifdef VBOX_WITH_USB
- *aEnabled = true;
-#else
- *aEnabled = false;
-#endif
+ *aType = m->bd->enmType;
return S_OK;
}
@@ -377,366 +269,27 @@ STDMETHODIMP USBController::COMGETTER(USBStandard)(USHORT *aUSBStandard)
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
- /* not accessing data -- no need to lock */
-
- /** @todo This is no longer correct */
- *aUSBStandard = 0x0101;
-
- return S_OK;
-}
-
-#ifndef VBOX_WITH_USB
-/**
- * Fake class for build without USB.
- * We need an empty collection & enum for deviceFilters, that's all.
- */
-class ATL_NO_VTABLE USBDeviceFilter :
- public VirtualBoxBase,
- VBOX_SCRIPTABLE_IMPL(IUSBDeviceFilter)
-{
-public:
- DECLARE_NOT_AGGREGATABLE(USBDeviceFilter)
- DECLARE_PROTECT_FINAL_CONSTRUCT()
- BEGIN_COM_MAP(USBDeviceFilter)
- VBOX_DEFAULT_INTERFACE_ENTRIES(IUSBDeviceFilter)
- END_COM_MAP()
-
- DECLARE_EMPTY_CTOR_DTOR(USBDeviceFilter)
-
- // IUSBDeviceFilter properties
- STDMETHOD(COMGETTER(Name))(BSTR *aName);
- STDMETHOD(COMSETTER(Name))(IN_BSTR aName);
- STDMETHOD(COMGETTER(Active))(BOOL *aActive);
- STDMETHOD(COMSETTER(Active))(BOOL aActive);
- STDMETHOD(COMGETTER(VendorId))(BSTR *aVendorId);
- STDMETHOD(COMSETTER(VendorId))(IN_BSTR aVendorId);
- STDMETHOD(COMGETTER(ProductId))(BSTR *aProductId);
- STDMETHOD(COMSETTER(ProductId))(IN_BSTR aProductId);
- STDMETHOD(COMGETTER(Revision))(BSTR *aRevision);
- STDMETHOD(COMSETTER(Revision))(IN_BSTR aRevision);
- STDMETHOD(COMGETTER(Manufacturer))(BSTR *aManufacturer);
- STDMETHOD(COMSETTER(Manufacturer))(IN_BSTR aManufacturer);
- STDMETHOD(COMGETTER(Product))(BSTR *aProduct);
- STDMETHOD(COMSETTER(Product))(IN_BSTR aProduct);
- STDMETHOD(COMGETTER(SerialNumber))(BSTR *aSerialNumber);
- STDMETHOD(COMSETTER(SerialNumber))(IN_BSTR aSerialNumber);
- STDMETHOD(COMGETTER(Port))(BSTR *aPort);
- STDMETHOD(COMSETTER(Port))(IN_BSTR aPort);
- STDMETHOD(COMGETTER(Remote))(BSTR *aRemote);
- STDMETHOD(COMSETTER(Remote))(IN_BSTR aRemote);
- STDMETHOD(COMGETTER(MaskedInterfaces))(ULONG *aMaskedIfs);
- STDMETHOD(COMSETTER(MaskedInterfaces))(ULONG aMaskedIfs);
-};
-#endif /* !VBOX_WITH_USB */
-
-
-STDMETHODIMP USBController::COMGETTER(DeviceFilters)(ComSafeArrayOut(IUSBDeviceFilter *, aDevicesFilters))
-{
-#ifdef VBOX_WITH_USB
- CheckComArgOutSafeArrayPointerValid(aDevicesFilters);
-
- AutoCaller autoCaller(this);
- if(FAILED(autoCaller.rc())) return autoCaller.rc();
-
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
- SafeIfaceArray<IUSBDeviceFilter> collection(*m->llDeviceFilters.data());
- collection.detachTo(ComSafeArrayOutArg(aDevicesFilters));
-
- return S_OK;
-#else
- NOREF(aDevicesFilters);
-# ifndef RT_OS_WINDOWS
- NOREF(aDevicesFiltersSize);
-# endif
- ReturnComNotImplemented();
-#endif
-}
-
-// IUSBController methods
-/////////////////////////////////////////////////////////////////////////////
-
-STDMETHODIMP USBController::CreateDeviceFilter(IN_BSTR aName,
- IUSBDeviceFilter **aFilter)
-{
-#ifdef VBOX_WITH_USB
- CheckComArgOutPointerValid(aFilter);
-
- CheckComArgStrNotEmptyOrNull(aName);
-
- AutoCaller autoCaller(this);
- if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
- /* the machine needs to be mutable */
- AutoMutableStateDependency adep(m->pParent);
- if (FAILED(adep.rc())) return adep.rc();
-
- AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
- ComObjPtr<USBDeviceFilter> filter;
- filter.createObject();
- HRESULT rc = filter->init(this, aName);
- ComAssertComRCRetRC(rc);
- rc = filter.queryInterfaceTo(aFilter);
- AssertComRCReturnRC(rc);
-
- return S_OK;
-#else
- NOREF(aName);
- NOREF(aFilter);
- ReturnComNotImplemented();
-#endif
-}
-
-STDMETHODIMP USBController::InsertDeviceFilter(ULONG aPosition,
- IUSBDeviceFilter *aFilter)
-{
-#ifdef VBOX_WITH_USB
-
- CheckComArgNotNull(aFilter);
-
- AutoCaller autoCaller(this);
- if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
- /* the machine needs to be mutable */
- AutoMutableStateDependency adep(m->pParent);
- if (FAILED(adep.rc())) return adep.rc();
-
- AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
- ComObjPtr<USBDeviceFilter> filter = static_cast<USBDeviceFilter*>(aFilter);
- // @todo r=dj make sure the input object is actually from us
-// if (!filter)
-// return setError(E_INVALIDARG,
-// tr("The given USB device filter is not created within "
-// "this VirtualBox instance"));
-
- if (filter->mInList)
- return setError(VBOX_E_INVALID_OBJECT_STATE,
- tr("The given USB device filter is already in the list"));
-
- /* backup the list before modification */
- m->llDeviceFilters.backup();
-
- /* iterate to the position... */
- DeviceFilterList::iterator it;
- if (aPosition < m->llDeviceFilters->size())
+ switch (m->bd->enmType)
{
- it = m->llDeviceFilters->begin();
- std::advance(it, aPosition);
- }
- else
- it = m->llDeviceFilters->end();
- /* ...and insert */
- m->llDeviceFilters->insert(it, filter);
- filter->mInList = true;
-
- /* notify the proxy (only when it makes sense) */
- if (filter->getData().mActive && Global::IsOnline(adep.machineState())
- && filter->getData().mRemote.isMatch(false))
- {
- USBProxyService *service = m->pHost->usbProxyService();
- ComAssertRet(service, E_FAIL);
-
- ComAssertRet(filter->getId() == NULL, E_FAIL);
- filter->getId() = service->insertFilter(&filter->getData().mUSBFilter);
+ case USBControllerType_OHCI:
+ *aUSBStandard = 0x0101;
+ break;
+ case USBControllerType_EHCI:
+ *aUSBStandard = 0x0200;
+ break;
+ default:
+ AssertMsgFailedReturn(("Invalid controller type %d\n", m->bd->enmType),
+ E_FAIL);
}
- alock.release();
- AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS);
- m->pParent->setModified(Machine::IsModified_USB);
- mlock.release();
-
return S_OK;
-
-#else /* VBOX_WITH_USB */
-
- NOREF(aPosition);
- NOREF(aFilter);
- ReturnComNotImplemented();
-
-#endif /* VBOX_WITH_USB */
-}
-
-STDMETHODIMP USBController::RemoveDeviceFilter(ULONG aPosition,
- IUSBDeviceFilter **aFilter)
-{
-#ifdef VBOX_WITH_USB
-
- CheckComArgOutPointerValid(aFilter);
-
- AutoCaller autoCaller(this);
- if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
- /* the machine needs to be mutable */
- AutoMutableStateDependency adep(m->pParent);
- if (FAILED(adep.rc())) return adep.rc();
-
- AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
- if (!m->llDeviceFilters->size())
- return setError(E_INVALIDARG,
- tr("The USB device filter list is empty"));
-
- if (aPosition >= m->llDeviceFilters->size())
- return setError(E_INVALIDARG,
- tr("Invalid position: %lu (must be in range [0, %lu])"),
- aPosition, m->llDeviceFilters->size() - 1);
-
- /* backup the list before modification */
- m->llDeviceFilters.backup();
-
- ComObjPtr<USBDeviceFilter> filter;
- {
- /* iterate to the position... */
- DeviceFilterList::iterator it = m->llDeviceFilters->begin();
- std::advance(it, aPosition);
- /* ...get an element from there... */
- filter = *it;
- /* ...and remove */
- filter->mInList = false;
- m->llDeviceFilters->erase(it);
- }
-
- /* cancel sharing (make an independent copy of data) */
- filter->unshare();
-
- filter.queryInterfaceTo(aFilter);
-
- /* notify the proxy (only when it makes sense) */
- if (filter->getData().mActive && Global::IsOnline(adep.machineState())
- && filter->getData().mRemote.isMatch(false))
- {
- USBProxyService *service = m->pHost->usbProxyService();
- ComAssertRet(service, E_FAIL);
-
- ComAssertRet(filter->getId() != NULL, E_FAIL);
- service->removeFilter(filter->getId());
- filter->getId() = NULL;
- }
-
- alock.release();
- AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS);
- m->pParent->setModified(Machine::IsModified_USB);
- mlock.release();
-
- return S_OK;
-
-#else /* VBOX_WITH_USB */
-
- NOREF(aPosition);
- NOREF(aFilter);
- ReturnComNotImplemented();
-
-#endif /* VBOX_WITH_USB */
}
// public methods only for internal purposes
/////////////////////////////////////////////////////////////////////////////
-/**
- * Loads settings from the given machine node.
- * May be called once right after this object creation.
- *
- * @param aMachineNode <Machine> node.
- *
- * @note Does not lock "this" as Machine::loadHardware, which calls this, does not lock either.
- */
-HRESULT USBController::loadSettings(const settings::USBController &data)
-{
- AutoCaller autoCaller(this);
- AssertComRCReturnRC(autoCaller.rc());
-
- /* Note: we assume that the default values for attributes of optional
- * nodes are assigned in the Data::Data() constructor and don't do it
- * here. It implies that this method may only be called after constructing
- * a new BIOSSettings object while all its data fields are in the default
- * values. Exceptions are fields whose creation time defaults don't match
- * values that should be applied when these fields are not explicitly set
- * in the settings file (for backwards compatibility reasons). This takes
- * place when a setting of a newly created object must default to A while
- * the same setting of an object loaded from the old settings file must
- * default to B. */
-
- m->bd->fEnabled = data.fEnabled;
- m->bd->fEnabledEHCI = data.fEnabledEHCI;
-
-#ifdef VBOX_WITH_USB
- for (settings::USBDeviceFiltersList::const_iterator it = data.llDeviceFilters.begin();
- it != data.llDeviceFilters.end();
- ++it)
- {
- const settings::USBDeviceFilter &f = *it;
- ComObjPtr<USBDeviceFilter> pFilter;
- pFilter.createObject();
- HRESULT rc = pFilter->init(this, // parent
- f);
- if (FAILED(rc)) return rc;
-
- m->llDeviceFilters->push_back(pFilter);
- pFilter->mInList = true;
- }
-#endif /* VBOX_WITH_USB */
-
- return S_OK;
-}
-
-/**
- * Saves settings to the given machine node.
- *
- * @param aMachineNode <Machine> node.
- *
- * @note Locks this object for reading.
- */
-HRESULT USBController::saveSettings(settings::USBController &data)
-{
- AutoCaller autoCaller(this);
- if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
- AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
- data.fEnabled = !!m->bd->fEnabled;
- data.fEnabledEHCI = !!m->bd->fEnabledEHCI;
-
-#ifdef VBOX_WITH_USB
- data.llDeviceFilters.clear();
-
- for (DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
- it != m->llDeviceFilters->end();
- ++it)
- {
- AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS);
- const USBDeviceFilter::Data &filterData = (*it)->getData();
-
- Bstr str;
-
- settings::USBDeviceFilter f;
- f.strName = filterData.mName;
- f.fActive = !!filterData.mActive;
- (*it)->COMGETTER(VendorId)(str.asOutParam());
- f.strVendorId = str;
- (*it)->COMGETTER(ProductId)(str.asOutParam());
- f.strProductId = str;
- (*it)->COMGETTER(Revision)(str.asOutParam());
- f.strRevision = str;
- (*it)->COMGETTER(Manufacturer)(str.asOutParam());
- f.strManufacturer = str;
- (*it)->COMGETTER(Product)(str.asOutParam());
- f.strProduct = str;
- (*it)->COMGETTER(SerialNumber)(str.asOutParam());
- f.strSerialNumber = str;
- (*it)->COMGETTER(Port)(str.asOutParam());
- f.strPort = str;
- f.strRemote = filterData.mRemote.string();
- f.ulMaskedInterfaces = filterData.mMaskedIfs;
-
- data.llDeviceFilters.push_back(f);
- }
-#endif /* VBOX_WITH_USB */
-
- return S_OK;
-}
-
/** @note Locks objects for writing! */
void USBController::rollback()
{
@@ -750,82 +303,6 @@ void USBController::rollback()
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
m->bd.rollback();
-
-#ifdef VBOX_WITH_USB
-
- if (m->llDeviceFilters.isBackedUp())
- {
- USBProxyService *service = m->pHost->usbProxyService();
- Assert(service);
-
- /* uninitialize all new filters (absent in the backed up list) */
- DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
- DeviceFilterList *backedList = m->llDeviceFilters.backedUpData();
- while (it != m->llDeviceFilters->end())
- {
- if (std::find(backedList->begin(), backedList->end(), *it) ==
- backedList->end())
- {
- /* notify the proxy (only when it makes sense) */
- if ((*it)->getData().mActive &&
- Global::IsOnline(adep.machineState())
- && (*it)->getData().mRemote.isMatch(false))
- {
- USBDeviceFilter *filter = *it;
- Assert(filter->getId() != NULL);
- service->removeFilter(filter->getId());
- filter->getId() = NULL;
- }
-
- (*it)->uninit();
- }
- ++it;
- }
-
- if (Global::IsOnline(adep.machineState()))
- {
- /* find all removed old filters (absent in the new list)
- * and insert them back to the USB proxy */
- it = backedList->begin();
- while (it != backedList->end())
- {
- if (std::find(m->llDeviceFilters->begin(), m->llDeviceFilters->end(), *it) ==
- m->llDeviceFilters->end())
- {
- /* notify the proxy (only when necessary) */
- if ((*it)->getData().mActive
- && (*it)->getData().mRemote.isMatch(false))
- {
- USBDeviceFilter *flt = *it; /* resolve ambiguity */
- Assert(flt->getId() == NULL);
- flt->getId() = service->insertFilter(&flt->getData().mUSBFilter);
- }
- }
- ++it;
- }
- }
-
- /* restore the list */
- m->llDeviceFilters.rollback();
- }
-
- /* here we don't depend on the machine state any more */
- adep.release();
-
- /* rollback any changes to filters after restoring the list */
- DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
- while (it != m->llDeviceFilters->end())
- {
- if ((*it)->isModified())
- {
- (*it)->rollback();
- /* call this to notify the USB proxy about changes */
- onDeviceFilterChange(*it);
- }
- ++it;
- }
-
-#endif /* VBOX_WITH_USB */
}
/**
@@ -856,82 +333,6 @@ void USBController::commit()
m->pPeer->m->bd.attach(m->bd);
}
}
-
-#ifdef VBOX_WITH_USB
- bool commitFilters = false;
-
- if (m->llDeviceFilters.isBackedUp())
- {
- m->llDeviceFilters.commit();
-
- /* apply changes to peer */
- if (m->pPeer)
- {
- AutoWriteLock peerlock(m->pPeer COMMA_LOCKVAL_SRC_POS);
-
- /* commit all changes to new filters (this will reshare data with
- * peers for those who have peers) */
- DeviceFilterList *newList = new DeviceFilterList();
- DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
- while (it != m->llDeviceFilters->end())
- {
- (*it)->commit();
-
- /* look if this filter has a peer filter */
- ComObjPtr<USBDeviceFilter> peer = (*it)->peer();
- if (!peer)
- {
- /* no peer means the filter is a newly created one;
- * create a peer owning data this filter share it with */
- peer.createObject();
- peer->init(m->pPeer, *it, true /* aReshare */);
- }
- else
- {
- /* remove peer from the old list */
- m->pPeer->m->llDeviceFilters->remove(peer);
- }
- /* and add it to the new list */
- newList->push_back(peer);
-
- ++it;
- }
-
- /* uninit old peer's filters that are left */
- it = m->pPeer->m->llDeviceFilters->begin();
- while (it != m->pPeer->m->llDeviceFilters->end())
- {
- (*it)->uninit();
- ++it;
- }
-
- /* attach new list of filters to our peer */
- m->pPeer->m->llDeviceFilters.attach(newList);
- }
- else
- {
- /* we have no peer (our parent is the newly created machine);
- * just commit changes to filters */
- commitFilters = true;
- }
- }
- else
- {
- /* the list of filters itself is not changed,
- * just commit changes to filters themselves */
- commitFilters = true;
- }
-
- if (commitFilters)
- {
- DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
- while (it != m->llDeviceFilters->end())
- {
- (*it)->commit();
- ++it;
- }
- }
-#endif /* VBOX_WITH_USB */
}
/**
@@ -963,295 +364,56 @@ void USBController::copyFrom(USBController *aThat)
/* this will back up current data */
m->bd.assignCopy(aThat->m->bd);
-
-#ifdef VBOX_WITH_USB
-
- /* Note that we won't inform the USB proxy about new filters since the VM is
- * not running when we are here and therefore no need to do so */
-
- /* create private copies of all filters */
- m->llDeviceFilters.backup();
- m->llDeviceFilters->clear();
- for (DeviceFilterList::const_iterator it = aThat->m->llDeviceFilters->begin();
- it != aThat->m->llDeviceFilters->end();
- ++it)
- {
- ComObjPtr<USBDeviceFilter> filter;
- filter.createObject();
- filter->initCopy(this, *it);
- m->llDeviceFilters->push_back(filter);
- }
-
-#endif /* VBOX_WITH_USB */
}
-#ifdef VBOX_WITH_USB
-
/**
- * Called by setter methods of all USB device filters.
+ * Cancels sharing (if any) by making an independent copy of data.
+ * This operation also resets this object's peer to NULL.
*
- * @note Locks nothing.
+ * @note Locks this object for writing, together with the peer object
+ * represented by @a aThat (locked for reading).
*/
-HRESULT USBController::onDeviceFilterChange(USBDeviceFilter *aFilter,
- BOOL aActiveChanged /* = FALSE */)
+void USBController::unshare()
{
+ /* sanity */
AutoCaller autoCaller(this);
- AssertComRCReturnRC(autoCaller.rc());
+ AssertComRCReturnVoid (autoCaller.rc());
- /* we need the machine state */
- AutoAnyStateDependency adep(m->pParent);
- AssertComRCReturnRC(adep.rc());
-
- /* nothing to do if the machine isn't running */
- if (!Global::IsOnline(adep.machineState()))
- return S_OK;
+ /* sanity too */
+ AutoCaller peerCaller (m->pPeer);
+ AssertComRCReturnVoid (peerCaller.rc());
- /* we don't modify our data fields -- no need to lock */
+ /* peer is not modified, lock it for reading (m->pPeer is "master" so locked
+ * first) */
+ AutoReadLock rl(m->pPeer COMMA_LOCKVAL_SRC_POS);
+ AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
- if ( aFilter->mInList
- && m->pParent->isRegistered())
+ if (m->bd.isShared())
{
- USBProxyService *service = m->pHost->usbProxyService();
- ComAssertRet(service, E_FAIL);
-
- if (aActiveChanged)
- {
- if (aFilter->getData().mRemote.isMatch(false))
- {
- /* insert/remove the filter from the proxy */
- if (aFilter->getData().mActive)
- {
- ComAssertRet(aFilter->getId() == NULL, E_FAIL);
- aFilter->getId() = service->insertFilter(&aFilter->getData().mUSBFilter);
- }
- else
- {
- ComAssertRet(aFilter->getId() != NULL, E_FAIL);
- service->removeFilter(aFilter->getId());
- aFilter->getId() = NULL;
- }
- }
- }
- else
- {
- if (aFilter->getData().mActive)
- {
- /* update the filter in the proxy */
- ComAssertRet(aFilter->getId() != NULL, E_FAIL);
- service->removeFilter(aFilter->getId());
- if (aFilter->getData().mRemote.isMatch(false))
- {
- aFilter->getId() = service->insertFilter(&aFilter->getData().mUSBFilter);
- }
- }
- }
- }
-
- return S_OK;
-}
-
-/**
- * Returns true if the given USB device matches to at least one of
- * this controller's USB device filters.
- *
- * A HostUSBDevice specific version.
- *
- * @note Locks this object for reading.
- */
-bool USBController::hasMatchingFilter(const ComObjPtr<HostUSBDevice> &aDevice, ULONG *aMaskedIfs)
-{
- AutoCaller autoCaller(this);
- AssertComRCReturn(autoCaller.rc(), false);
+ if (!m->bd.isBackedUp())
+ m->bd.backup();
- AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
- /* Disabled USB controllers cannot actually work with USB devices */
- if (!m->bd->fEnabled)
- return false;
-
- /* apply self filters */
- for (DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
- it != m->llDeviceFilters->end();
- ++it)
- {
- AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS);
- if (aDevice->isMatch((*it)->getData()))
- {
- *aMaskedIfs = (*it)->getData().mMaskedIfs;
- return true;
- }
+ m->bd.commit();
}
- return false;
+ unconst(m->pPeer) = NULL;
}
-/**
- * Returns true if the given USB device matches to at least one of
- * this controller's USB device filters.
- *
- * A generic version that accepts any IUSBDevice on input.
- *
- * @note
- * This method MUST correlate with HostUSBDevice::isMatch()
- * in the sense of the device matching logic.
- *
- * @note Locks this object for reading.
- */
-bool USBController::hasMatchingFilter(IUSBDevice *aUSBDevice, ULONG *aMaskedIfs)
+const Utf8Str& USBController::getName() const
{
- LogFlowThisFuncEnter();
-
- AutoCaller autoCaller(this);
- AssertComRCReturn(autoCaller.rc(), false);
-
- AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
- /* Disabled USB controllers cannot actually work with USB devices */
- if (!m->bd->fEnabled)
- return false;
-
- HRESULT rc = S_OK;
-
- /* query fields */
- USBFILTER dev;
- USBFilterInit(&dev, USBFILTERTYPE_CAPTURE);
-
- USHORT vendorId = 0;
- rc = aUSBDevice->COMGETTER(VendorId)(&vendorId);
- ComAssertComRCRet(rc, false);
- ComAssertRet(vendorId, false);
- int vrc = USBFilterSetNumExact(&dev, USBFILTERIDX_VENDOR_ID, vendorId, true); AssertRC(vrc);
-
- USHORT productId = 0;
- rc = aUSBDevice->COMGETTER(ProductId)(&productId);
- ComAssertComRCRet(rc, false);
- vrc = USBFilterSetNumExact(&dev, USBFILTERIDX_PRODUCT_ID, productId, true); AssertRC(vrc);
-
- USHORT revision;
- rc = aUSBDevice->COMGETTER(Revision)(&revision);
- ComAssertComRCRet(rc, false);
- vrc = USBFilterSetNumExact(&dev, USBFILTERIDX_DEVICE, revision, true); AssertRC(vrc);
-
- Bstr manufacturer;
- rc = aUSBDevice->COMGETTER(Manufacturer)(manufacturer.asOutParam());
- ComAssertComRCRet(rc, false);
- if (!manufacturer.isEmpty())
- USBFilterSetStringExact(&dev, USBFILTERIDX_MANUFACTURER_STR, Utf8Str(manufacturer).c_str(), true);
-
- Bstr product;
- rc = aUSBDevice->COMGETTER(Product)(product.asOutParam());
- ComAssertComRCRet(rc, false);
- if (!product.isEmpty())
- USBFilterSetStringExact(&dev, USBFILTERIDX_PRODUCT_STR, Utf8Str(product).c_str(), true);
-
- Bstr serialNumber;
- rc = aUSBDevice->COMGETTER(SerialNumber)(serialNumber.asOutParam());
- ComAssertComRCRet(rc, false);
- if (!serialNumber.isEmpty())
- USBFilterSetStringExact(&dev, USBFILTERIDX_SERIAL_NUMBER_STR, Utf8Str(serialNumber).c_str(), true);
-
- Bstr address;
- rc = aUSBDevice->COMGETTER(Address)(address.asOutParam());
- ComAssertComRCRet(rc, false);
-
- USHORT port = 0;
- rc = aUSBDevice->COMGETTER(Port)(&port);
- ComAssertComRCRet(rc, false);
- USBFilterSetNumExact(&dev, USBFILTERIDX_PORT, port, true);
-
- BOOL remote = FALSE;
- rc = aUSBDevice->COMGETTER(Remote)(&remote);
- ComAssertComRCRet(rc, false);
- ComAssertRet(remote == TRUE, false);
-
- bool match = false;
-
- /* apply self filters */
- for (DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
- it != m->llDeviceFilters->end();
- ++it)
- {
- AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS);
- const USBDeviceFilter::Data &aData = (*it)->getData();
-
- if (!aData.mActive)
- continue;
- if (!aData.mRemote.isMatch(remote))
- continue;
- if (!USBFilterMatch(&aData.mUSBFilter, &dev))
- continue;
-
- match = true;
- *aMaskedIfs = aData.mMaskedIfs;
- break;
- }
-
- LogFlowThisFunc(("returns: %d\n", match));
- LogFlowThisFuncLeave();
-
- return match;
+ return m->bd->strName;
}
-/**
- * Notifies the proxy service about all filters as requested by the
- * @a aInsertFilters argument.
- *
- * @param aInsertFilters @c true to insert filters, @c false to remove.
- *
- * @note Locks this object for reading.
- */
-HRESULT USBController::notifyProxy(bool aInsertFilters)
+USBControllerType_T USBController::getControllerType() const
{
- LogFlowThisFunc(("aInsertFilters=%RTbool\n", aInsertFilters));
-
- AutoCaller autoCaller(this);
- AssertComRCReturn(autoCaller.rc(), false);
-
- AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
- USBProxyService *service = m->pHost->usbProxyService();
- AssertReturn(service, E_FAIL);
-
- DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
- while (it != m->llDeviceFilters->end())
- {
- USBDeviceFilter *flt = *it; /* resolve ambiguity (for ComPtr below) */
-
- /* notify the proxy (only if the filter is active) */
- if ( flt->getData().mActive
- && flt->getData().mRemote.isMatch(false) /* and if the filter is NOT remote */
- )
- {
- if (aInsertFilters)
- {
- AssertReturn(flt->getId() == NULL, E_FAIL);
- flt->getId() = service->insertFilter(&flt->getData().mUSBFilter);
- }
- else
- {
- /* It's possible that the given filter was not inserted the proxy
- * when this method gets called (as a result of an early VM
- * process crash for example. So, don't assert that ID != NULL. */
- if (flt->getId() != NULL)
- {
- service->removeFilter(flt->getId());
- flt->getId() = NULL;
- }
- }
- }
- ++it;
- }
-
- return S_OK;
+ return m->bd->enmType;
}
-Machine* USBController::getMachine()
+ComObjPtr<USBController> USBController::getPeer()
{
- return m->pParent;
+ return m->pPeer;
}
-#endif /* VBOX_WITH_USB */
-
// private methods
/////////////////////////////////////////////////////////////////////////////
/* vi: set tabstop=4 shiftwidth=4 expandtab: */
diff --git a/src/VBox/Main/src-server/USBDeviceFilterImpl.cpp b/src/VBox/Main/src-server/USBDeviceFilterImpl.cpp
index 0c8046e9..47857b4e 100644
--- a/src/VBox/Main/src-server/USBDeviceFilterImpl.cpp
+++ b/src/VBox/Main/src-server/USBDeviceFilterImpl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -16,7 +16,7 @@
*/
#include "USBDeviceFilterImpl.h"
-#include "USBControllerImpl.h"
+#include "USBDeviceFiltersImpl.h"
#include "MachineImpl.h"
#include "HostImpl.h"
@@ -203,7 +203,7 @@ void USBDeviceFilter::FinalRelease()
*
* @param aParent Handle of the parent object.
*/
-HRESULT USBDeviceFilter::init(USBController *aParent,
+HRESULT USBDeviceFilter::init(USBDeviceFilters *aParent,
const settings::USBDeviceFilter &data)
{
LogFlowThisFunc(("aParent=%p\n", aParent));
@@ -277,7 +277,7 @@ HRESULT USBDeviceFilter::init(USBController *aParent,
*
* @param aParent Handle of the parent object.
*/
-HRESULT USBDeviceFilter::init(USBController *aParent, IN_BSTR aName)
+HRESULT USBDeviceFilter::init(USBDeviceFilters *aParent, IN_BSTR aName)
{
LogFlowThisFunc(("aParent=%p\n", aParent));
@@ -326,7 +326,7 @@ HRESULT USBDeviceFilter::init(USBController *aParent, IN_BSTR aName)
* @note Locks @a aThat object for writing if @a aReshare is @c true, or for
* reading if @a aReshare is false.
*/
-HRESULT USBDeviceFilter::init (USBController *aParent, USBDeviceFilter *aThat,
+HRESULT USBDeviceFilter::init (USBDeviceFilters *aParent, USBDeviceFilter *aThat,
bool aReshare /* = false */)
{
LogFlowThisFunc(("aParent=%p, aThat=%p, aReshare=%RTbool\n",
@@ -379,7 +379,7 @@ HRESULT USBDeviceFilter::init (USBController *aParent, USBDeviceFilter *aThat,
*
* @note Locks @a aThat object for reading.
*/
-HRESULT USBDeviceFilter::initCopy (USBController *aParent, USBDeviceFilter *aThat)
+HRESULT USBDeviceFilter::initCopy (USBDeviceFilters *aParent, USBDeviceFilter *aThat)
{
LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
diff --git a/src/VBox/Main/src-server/USBDeviceFiltersImpl.cpp b/src/VBox/Main/src-server/USBDeviceFiltersImpl.cpp
new file mode 100644
index 00000000..09b42f5c
--- /dev/null
+++ b/src/VBox/Main/src-server/USBDeviceFiltersImpl.cpp
@@ -0,0 +1,1089 @@
+/* $Id: USBDeviceFiltersImpl.cpp $ */
+/** @file
+ * Implementation of IUSBController.
+ */
+
+/*
+ * Copyright (C) 2005-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "USBDeviceFiltersImpl.h"
+
+#include "Global.h"
+#include "MachineImpl.h"
+#include "VirtualBoxImpl.h"
+#include "HostImpl.h"
+#ifdef VBOX_WITH_USB
+# include "USBDeviceImpl.h"
+# include "HostUSBDeviceImpl.h"
+# include "USBProxyService.h"
+# include "USBDeviceFilterImpl.h"
+#endif
+
+#include <iprt/string.h>
+#include <iprt/cpp/utils.h>
+
+#include <VBox/err.h>
+#include <VBox/settings.h>
+#include <VBox/com/array.h>
+
+#include <algorithm>
+
+#include "AutoStateDep.h"
+#include "AutoCaller.h"
+#include "Logging.h"
+
+// defines
+/////////////////////////////////////////////////////////////////////////////
+
+typedef std::list< ComObjPtr<USBDeviceFilter> > DeviceFilterList;
+
+struct USBDeviceFilters::Data
+{
+ Data(Machine *pMachine)
+ : pParent(pMachine),
+ pHost(pMachine->getVirtualBox()->host())
+ { }
+
+ ~Data()
+ {};
+
+ Machine * const pParent;
+ Host * const pHost;
+
+ // peer machine's USB device filters list
+ const ComObjPtr<USBDeviceFilters> pPeer;
+
+#ifdef VBOX_WITH_USB
+ // List of device filters.
+ Backupable<DeviceFilterList> llDeviceFilters;
+#endif
+};
+
+
+
+// constructor / destructor
+/////////////////////////////////////////////////////////////////////////////
+
+DEFINE_EMPTY_CTOR_DTOR(USBDeviceFilters)
+
+HRESULT USBDeviceFilters::FinalConstruct()
+{
+ return BaseFinalConstruct();
+}
+
+void USBDeviceFilters::FinalRelease()
+{
+ uninit();
+ BaseFinalRelease();
+}
+
+// public initializer/uninitializer for internal purposes only
+/////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Initializes the USB controller object.
+ *
+ * @returns COM result indicator.
+ * @param aParent Pointer to our parent object.
+ */
+HRESULT USBDeviceFilters::init(Machine *aParent)
+{
+ LogFlowThisFunc(("aParent=%p\n", aParent));
+
+ ComAssertRet(aParent, E_INVALIDARG);
+
+ /* Enclose the state transition NotReady->InInit->Ready */
+ AutoInitSpan autoInitSpan(this);
+ AssertReturn(autoInitSpan.isOk(), E_FAIL);
+
+ m = new Data(aParent);
+
+ /* mPeer is left null */
+#ifdef VBOX_WITH_USB
+ m->llDeviceFilters.allocate();
+#endif
+
+ /* Confirm a successful initialization */
+ autoInitSpan.setSucceeded();
+
+ return S_OK;
+}
+
+/**
+ * Initializes the USB devic filters object given another USB filters object
+ * (a kind of copy constructor). This object shares data with
+ * the object passed as an argument.
+ *
+ * @returns COM result indicator.
+ * @param aParent Pointer to our parent object.
+ * @param aPeer The object to share.
+ *
+ * @note This object must be destroyed before the original object
+ * it shares data with is destroyed.
+ */
+HRESULT USBDeviceFilters::init(Machine *aParent, USBDeviceFilters *aPeer)
+{
+ LogFlowThisFunc(("aParent=%p, aPeer=%p\n", aParent, aPeer));
+
+ ComAssertRet(aParent && aPeer, E_INVALIDARG);
+
+ /* Enclose the state transition NotReady->InInit->Ready */
+ AutoInitSpan autoInitSpan(this);
+ AssertReturn(autoInitSpan.isOk(), E_FAIL);
+
+ m = new Data(aParent);
+
+ unconst(m->pPeer) = aPeer;
+
+ AutoWriteLock thatlock(aPeer COMMA_LOCKVAL_SRC_POS);
+
+#ifdef VBOX_WITH_USB
+ /* create copies of all filters */
+ m->llDeviceFilters.allocate();
+ DeviceFilterList::const_iterator it = aPeer->m->llDeviceFilters->begin();
+ while (it != aPeer->m->llDeviceFilters->end())
+ {
+ ComObjPtr<USBDeviceFilter> pFilter;
+ pFilter.createObject();
+ pFilter->init(this, *it);
+ m->llDeviceFilters->push_back(pFilter);
+ ++it;
+ }
+#endif /* VBOX_WITH_USB */
+
+ /* Confirm a successful initialization */
+ autoInitSpan.setSucceeded();
+
+ return S_OK;
+}
+
+
+/**
+ * Initializes the USB controller object given another guest object
+ * (a kind of copy constructor). This object makes a private copy of data
+ * of the original object passed as an argument.
+ */
+HRESULT USBDeviceFilters::initCopy(Machine *aParent, USBDeviceFilters *aPeer)
+{
+ LogFlowThisFunc(("aParent=%p, aPeer=%p\n", aParent, aPeer));
+
+ ComAssertRet(aParent && aPeer, E_INVALIDARG);
+
+ /* Enclose the state transition NotReady->InInit->Ready */
+ AutoInitSpan autoInitSpan(this);
+ AssertReturn(autoInitSpan.isOk(), E_FAIL);
+
+ m = new Data(aParent);
+
+ /* mPeer is left null */
+
+ AutoWriteLock thatlock(aPeer COMMA_LOCKVAL_SRC_POS);
+
+#ifdef VBOX_WITH_USB
+ /* create private copies of all filters */
+ m->llDeviceFilters.allocate();
+ DeviceFilterList::const_iterator it = aPeer->m->llDeviceFilters->begin();
+ while (it != aPeer->m->llDeviceFilters->end())
+ {
+ ComObjPtr<USBDeviceFilter> pFilter;
+ pFilter.createObject();
+ pFilter->initCopy(this, *it);
+ m->llDeviceFilters->push_back(pFilter);
+ ++it;
+ }
+#endif /* VBOX_WITH_USB */
+
+ /* Confirm a successful initialization */
+ autoInitSpan.setSucceeded();
+
+ return S_OK;
+}
+
+
+/**
+ * Uninitializes the instance and sets the ready flag to FALSE.
+ * Called either from FinalRelease() or by the parent when it gets destroyed.
+ */
+void USBDeviceFilters::uninit()
+{
+ LogFlowThisFunc(("\n"));
+
+ /* Enclose the state transition Ready->InUninit->NotReady */
+ AutoUninitSpan autoUninitSpan(this);
+ if (autoUninitSpan.uninitDone())
+ return;
+
+#ifdef VBOX_WITH_USB
+ // uninit all device filters on the list (it's a standard std::list not an ObjectsList
+ // so we must uninit() manually)
+ for (DeviceFilterList::iterator it = m->llDeviceFilters->begin();
+ it != m->llDeviceFilters->end();
+ ++it)
+ (*it)->uninit();
+
+ m->llDeviceFilters.free();
+#endif
+
+ unconst(m->pPeer) = NULL;
+ unconst(m->pParent) = NULL;
+
+ delete m;
+ m = NULL;
+}
+
+
+// IUSBDeviceFilters properties
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef VBOX_WITH_USB
+/**
+ * Fake class for build without USB.
+ * We need an empty collection & enum for deviceFilters, that's all.
+ */
+class ATL_NO_VTABLE USBDeviceFilter :
+ public VirtualBoxBase,
+ VBOX_SCRIPTABLE_IMPL(IUSBDeviceFilter)
+{
+public:
+ DECLARE_NOT_AGGREGATABLE(USBDeviceFilter)
+ DECLARE_PROTECT_FINAL_CONSTRUCT()
+ BEGIN_COM_MAP(USBDeviceFilter)
+ VBOX_DEFAULT_INTERFACE_ENTRIES(IUSBDeviceFilter)
+ END_COM_MAP()
+
+ DECLARE_EMPTY_CTOR_DTOR(USBDeviceFilter)
+
+ // IUSBDeviceFilter properties
+ STDMETHOD(COMGETTER(Name))(BSTR *aName);
+ STDMETHOD(COMSETTER(Name))(IN_BSTR aName);
+ STDMETHOD(COMGETTER(Active))(BOOL *aActive);
+ STDMETHOD(COMSETTER(Active))(BOOL aActive);
+ STDMETHOD(COMGETTER(VendorId))(BSTR *aVendorId);
+ STDMETHOD(COMSETTER(VendorId))(IN_BSTR aVendorId);
+ STDMETHOD(COMGETTER(ProductId))(BSTR *aProductId);
+ STDMETHOD(COMSETTER(ProductId))(IN_BSTR aProductId);
+ STDMETHOD(COMGETTER(Revision))(BSTR *aRevision);
+ STDMETHOD(COMSETTER(Revision))(IN_BSTR aRevision);
+ STDMETHOD(COMGETTER(Manufacturer))(BSTR *aManufacturer);
+ STDMETHOD(COMSETTER(Manufacturer))(IN_BSTR aManufacturer);
+ STDMETHOD(COMGETTER(Product))(BSTR *aProduct);
+ STDMETHOD(COMSETTER(Product))(IN_BSTR aProduct);
+ STDMETHOD(COMGETTER(SerialNumber))(BSTR *aSerialNumber);
+ STDMETHOD(COMSETTER(SerialNumber))(IN_BSTR aSerialNumber);
+ STDMETHOD(COMGETTER(Port))(BSTR *aPort);
+ STDMETHOD(COMSETTER(Port))(IN_BSTR aPort);
+ STDMETHOD(COMGETTER(Remote))(BSTR *aRemote);
+ STDMETHOD(COMSETTER(Remote))(IN_BSTR aRemote);
+ STDMETHOD(COMGETTER(MaskedInterfaces))(ULONG *aMaskedIfs);
+ STDMETHOD(COMSETTER(MaskedInterfaces))(ULONG aMaskedIfs);
+};
+#endif /* !VBOX_WITH_USB */
+
+
+STDMETHODIMP USBDeviceFilters::COMGETTER(DeviceFilters)(ComSafeArrayOut(IUSBDeviceFilter *, aDevicesFilters))
+{
+#ifdef VBOX_WITH_USB
+ CheckComArgOutSafeArrayPointerValid(aDevicesFilters);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ SafeIfaceArray<IUSBDeviceFilter> collection(*m->llDeviceFilters.data());
+ collection.detachTo(ComSafeArrayOutArg(aDevicesFilters));
+
+ return S_OK;
+#else
+ NOREF(aDevicesFilters);
+# ifndef RT_OS_WINDOWS
+ NOREF(aDevicesFiltersSize);
+# endif
+ ReturnComNotImplemented();
+#endif
+}
+
+// IUSBDeviceFilters methods
+/////////////////////////////////////////////////////////////////////////////
+
+STDMETHODIMP USBDeviceFilters::CreateDeviceFilter(IN_BSTR aName,
+ IUSBDeviceFilter **aFilter)
+{
+#ifdef VBOX_WITH_USB
+ CheckComArgOutPointerValid(aFilter);
+
+ CheckComArgStrNotEmptyOrNull(aName);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ /* the machine needs to be mutable */
+ AutoMutableStateDependency adep(m->pParent);
+ if (FAILED(adep.rc())) return adep.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ ComObjPtr<USBDeviceFilter> pFilter;
+ pFilter.createObject();
+ HRESULT rc = pFilter->init(this, aName);
+ ComAssertComRCRetRC(rc);
+ rc = pFilter.queryInterfaceTo(aFilter);
+ AssertComRCReturnRC(rc);
+
+ return S_OK;
+#else
+ NOREF(aName);
+ NOREF(aFilter);
+ ReturnComNotImplemented();
+#endif
+}
+
+STDMETHODIMP USBDeviceFilters::InsertDeviceFilter(ULONG aPosition,
+ IUSBDeviceFilter *aFilter)
+{
+#ifdef VBOX_WITH_USB
+
+ CheckComArgNotNull(aFilter);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ /* the machine needs to be mutable */
+ AutoMutableStateDependency adep(m->pParent);
+ if (FAILED(adep.rc())) return adep.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ ComObjPtr<USBDeviceFilter> pFilter = static_cast<USBDeviceFilter*>(aFilter);
+
+ if (pFilter->mInList)
+ return setError(VBOX_E_INVALID_OBJECT_STATE,
+ tr("The given USB device pFilter is already in the list"));
+
+ /* backup the list before modification */
+ m->llDeviceFilters.backup();
+
+ /* iterate to the position... */
+ DeviceFilterList::iterator it;
+ if (aPosition < m->llDeviceFilters->size())
+ {
+ it = m->llDeviceFilters->begin();
+ std::advance(it, aPosition);
+ }
+ else
+ it = m->llDeviceFilters->end();
+ /* ...and insert */
+ m->llDeviceFilters->insert(it, pFilter);
+ pFilter->mInList = true;
+
+ /* notify the proxy (only when it makes sense) */
+ if (pFilter->getData().mActive && Global::IsOnline(adep.machineState())
+ && pFilter->getData().mRemote.isMatch(false))
+ {
+ USBProxyService *pProxySvc = m->pHost->usbProxyService();
+ ComAssertRet(pProxySvc, E_FAIL);
+
+ ComAssertRet(pFilter->getId() == NULL, E_FAIL);
+ pFilter->getId() = pProxySvc->insertFilter(&pFilter->getData().mUSBFilter);
+ }
+
+ alock.release();
+ AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS);
+ m->pParent->setModified(Machine::IsModified_USB);
+ mlock.release();
+
+ return S_OK;
+
+#else /* VBOX_WITH_USB */
+
+ NOREF(aPosition);
+ NOREF(aFilter);
+ ReturnComNotImplemented();
+
+#endif /* VBOX_WITH_USB */
+}
+
+STDMETHODIMP USBDeviceFilters::RemoveDeviceFilter(ULONG aPosition,
+ IUSBDeviceFilter **aFilter)
+{
+#ifdef VBOX_WITH_USB
+
+ CheckComArgOutPointerValid(aFilter);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ /* the machine needs to be mutable */
+ AutoMutableStateDependency adep(m->pParent);
+ if (FAILED(adep.rc())) return adep.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (!m->llDeviceFilters->size())
+ return setError(E_INVALIDARG,
+ tr("The USB device pFilter list is empty"));
+
+ if (aPosition >= m->llDeviceFilters->size())
+ return setError(E_INVALIDARG,
+ tr("Invalid position: %lu (must be in range [0, %lu])"),
+ aPosition, m->llDeviceFilters->size() - 1);
+
+ /* backup the list before modification */
+ m->llDeviceFilters.backup();
+
+ ComObjPtr<USBDeviceFilter> pFilter;
+ {
+ /* iterate to the position... */
+ DeviceFilterList::iterator it = m->llDeviceFilters->begin();
+ std::advance(it, aPosition);
+ /* ...get an element from there... */
+ pFilter = *it;
+ /* ...and remove */
+ pFilter->mInList = false;
+ m->llDeviceFilters->erase(it);
+ }
+
+ /* cancel sharing (make an independent copy of data) */
+ pFilter->unshare();
+
+ pFilter.queryInterfaceTo(aFilter);
+
+ /* notify the proxy (only when it makes sense) */
+ if (pFilter->getData().mActive && Global::IsOnline(adep.machineState())
+ && pFilter->getData().mRemote.isMatch(false))
+ {
+ USBProxyService *pProxySvc = m->pHost->usbProxyService();
+ ComAssertRet(pProxySvc, E_FAIL);
+
+ ComAssertRet(pFilter->getId() != NULL, E_FAIL);
+ pProxySvc->removeFilter(pFilter->getId());
+ pFilter->getId() = NULL;
+ }
+
+ alock.release();
+ AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS);
+ m->pParent->setModified(Machine::IsModified_USB);
+ mlock.release();
+
+ return S_OK;
+
+#else /* VBOX_WITH_USB */
+
+ NOREF(aPosition);
+ NOREF(aFilter);
+ ReturnComNotImplemented();
+
+#endif /* VBOX_WITH_USB */
+}
+
+// public methods only for internal purposes
+/////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Loads settings from the given machine node.
+ * May be called once right after this object creation.
+ *
+ * @param aMachineNode <Machine> node.
+ *
+ * @note Does not lock "this" as Machine::loadHardware, which calls this, does not lock either.
+ */
+HRESULT USBDeviceFilters::loadSettings(const settings::USB &data)
+{
+ AutoCaller autoCaller(this);
+ AssertComRCReturnRC(autoCaller.rc());
+
+ /* Note: we assume that the default values for attributes of optional
+ * nodes are assigned in the Data::Data() constructor and don't do it
+ * here. It implies that this method may only be called after constructing
+ * a new USBDeviceFilters object while all its data fields are in the default
+ * values. Exceptions are fields whose creation time defaults don't match
+ * values that should be applied when these fields are not explicitly set
+ * in the settings file (for backwards compatibility reasons). This takes
+ * place when a setting of a newly created object must default to A while
+ * the same setting of an object loaded from the old settings file must
+ * default to B. */
+
+#ifdef VBOX_WITH_USB
+ for (settings::USBDeviceFiltersList::const_iterator it = data.llDeviceFilters.begin();
+ it != data.llDeviceFilters.end();
+ ++it)
+ {
+ const settings::USBDeviceFilter &f = *it;
+ ComObjPtr<USBDeviceFilter> pFilter;
+ pFilter.createObject();
+ HRESULT rc = pFilter->init(this, // parent
+ f);
+ if (FAILED(rc)) return rc;
+
+ m->llDeviceFilters->push_back(pFilter);
+ pFilter->mInList = true;
+ }
+#endif /* VBOX_WITH_USB */
+
+ return S_OK;
+}
+
+/**
+ * Saves settings to the given machine node.
+ *
+ * @param aMachineNode <Machine> node.
+ *
+ * @note Locks this object for reading.
+ */
+HRESULT USBDeviceFilters::saveSettings(settings::USB &data)
+{
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+#ifdef VBOX_WITH_USB
+ data.llDeviceFilters.clear();
+
+ for (DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
+ it != m->llDeviceFilters->end();
+ ++it)
+ {
+ AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS);
+ const USBDeviceFilter::Data &filterData = (*it)->getData();
+
+ Bstr str;
+
+ settings::USBDeviceFilter f;
+ f.strName = filterData.mName;
+ f.fActive = !!filterData.mActive;
+ (*it)->COMGETTER(VendorId)(str.asOutParam());
+ f.strVendorId = str;
+ (*it)->COMGETTER(ProductId)(str.asOutParam());
+ f.strProductId = str;
+ (*it)->COMGETTER(Revision)(str.asOutParam());
+ f.strRevision = str;
+ (*it)->COMGETTER(Manufacturer)(str.asOutParam());
+ f.strManufacturer = str;
+ (*it)->COMGETTER(Product)(str.asOutParam());
+ f.strProduct = str;
+ (*it)->COMGETTER(SerialNumber)(str.asOutParam());
+ f.strSerialNumber = str;
+ (*it)->COMGETTER(Port)(str.asOutParam());
+ f.strPort = str;
+ f.strRemote = filterData.mRemote.string();
+ f.ulMaskedInterfaces = filterData.mMaskedIfs;
+
+ data.llDeviceFilters.push_back(f);
+ }
+#endif /* VBOX_WITH_USB */
+
+ return S_OK;
+}
+
+/** @note Locks objects for writing! */
+void USBDeviceFilters::rollback()
+{
+ AutoCaller autoCaller(this);
+ AssertComRCReturnVoid(autoCaller.rc());
+
+ /* we need the machine state */
+ AutoAnyStateDependency adep(m->pParent);
+ AssertComRCReturnVoid(adep.rc());
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+#ifdef VBOX_WITH_USB
+
+ if (m->llDeviceFilters.isBackedUp())
+ {
+ USBProxyService *pProxySvc = m->pHost->usbProxyService();
+ Assert(pProxySvc);
+
+ /* uninitialize all new filters (absent in the backed up list) */
+ DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
+ DeviceFilterList *backedList = m->llDeviceFilters.backedUpData();
+ while (it != m->llDeviceFilters->end())
+ {
+ if (std::find(backedList->begin(), backedList->end(), *it) ==
+ backedList->end())
+ {
+ /* notify the proxy (only when it makes sense) */
+ if ((*it)->getData().mActive &&
+ Global::IsOnline(adep.machineState())
+ && (*it)->getData().mRemote.isMatch(false))
+ {
+ USBDeviceFilter *pFilter = *it;
+ Assert(pFilter->getId() != NULL);
+ pProxySvc->removeFilter(pFilter->getId());
+ pFilter->getId() = NULL;
+ }
+
+ (*it)->uninit();
+ }
+ ++it;
+ }
+
+ if (Global::IsOnline(adep.machineState()))
+ {
+ /* find all removed old filters (absent in the new list)
+ * and insert them back to the USB proxy */
+ it = backedList->begin();
+ while (it != backedList->end())
+ {
+ if (std::find(m->llDeviceFilters->begin(), m->llDeviceFilters->end(), *it) ==
+ m->llDeviceFilters->end())
+ {
+ /* notify the proxy (only when necessary) */
+ if ((*it)->getData().mActive
+ && (*it)->getData().mRemote.isMatch(false))
+ {
+ USBDeviceFilter *pFilter = *it; /* resolve ambiguity */
+ Assert(pFilter->getId() == NULL);
+ pFilter->getId() = pProxySvc->insertFilter(&pFilter->getData().mUSBFilter);
+ }
+ }
+ ++it;
+ }
+ }
+
+ /* restore the list */
+ m->llDeviceFilters.rollback();
+ }
+
+ /* here we don't depend on the machine state any more */
+ adep.release();
+
+ /* rollback any changes to filters after restoring the list */
+ DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
+ while (it != m->llDeviceFilters->end())
+ {
+ if ((*it)->isModified())
+ {
+ (*it)->rollback();
+ /* call this to notify the USB proxy about changes */
+ onDeviceFilterChange(*it);
+ }
+ ++it;
+ }
+
+#endif /* VBOX_WITH_USB */
+}
+
+/**
+ * @note Locks this object for writing, together with the peer object (also
+ * for writing) if there is one.
+ */
+void USBDeviceFilters::commit()
+{
+ /* sanity */
+ AutoCaller autoCaller(this);
+ AssertComRCReturnVoid(autoCaller.rc());
+
+ /* sanity too */
+ AutoCaller peerCaller(m->pPeer);
+ AssertComRCReturnVoid(peerCaller.rc());
+
+ /* lock both for writing since we modify both (mPeer is "master" so locked
+ * first) */
+ AutoMultiWriteLock2 alock(m->pPeer, this COMMA_LOCKVAL_SRC_POS);
+
+#ifdef VBOX_WITH_USB
+ bool commitFilters = false;
+
+ if (m->llDeviceFilters.isBackedUp())
+ {
+ m->llDeviceFilters.commit();
+
+ /* apply changes to peer */
+ if (m->pPeer)
+ {
+ AutoWriteLock peerlock(m->pPeer COMMA_LOCKVAL_SRC_POS);
+
+ /* commit all changes to new filters (this will reshare data with
+ * peers for those who have peers) */
+ DeviceFilterList *newList = new DeviceFilterList();
+ DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
+ while (it != m->llDeviceFilters->end())
+ {
+ (*it)->commit();
+
+ /* look if this filter has a peer filter */
+ ComObjPtr<USBDeviceFilter> peer = (*it)->peer();
+ if (!peer)
+ {
+ /* no peer means the filter is a newly created one;
+ * create a peer owning data this filter share it with */
+ peer.createObject();
+ peer->init(m->pPeer, *it, true /* aReshare */);
+ }
+ else
+ {
+ /* remove peer from the old list */
+ m->pPeer->m->llDeviceFilters->remove(peer);
+ }
+ /* and add it to the new list */
+ newList->push_back(peer);
+
+ ++it;
+ }
+
+ /* uninit old peer's filters that are left */
+ it = m->pPeer->m->llDeviceFilters->begin();
+ while (it != m->pPeer->m->llDeviceFilters->end())
+ {
+ (*it)->uninit();
+ ++it;
+ }
+
+ /* attach new list of filters to our peer */
+ m->pPeer->m->llDeviceFilters.attach(newList);
+ }
+ else
+ {
+ /* we have no peer (our parent is the newly created machine);
+ * just commit changes to filters */
+ commitFilters = true;
+ }
+ }
+ else
+ {
+ /* the list of filters itself is not changed,
+ * just commit changes to filters themselves */
+ commitFilters = true;
+ }
+
+ if (commitFilters)
+ {
+ DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
+ while (it != m->llDeviceFilters->end())
+ {
+ (*it)->commit();
+ ++it;
+ }
+ }
+#endif /* VBOX_WITH_USB */
+}
+
+/**
+ * @note Locks this object for writing, together with the peer object
+ * represented by @a aThat (locked for reading).
+ */
+void USBDeviceFilters::copyFrom(USBDeviceFilters *aThat)
+{
+ AssertReturnVoid(aThat != NULL);
+
+ /* sanity */
+ AutoCaller autoCaller(this);
+ AssertComRCReturnVoid(autoCaller.rc());
+
+ /* sanity too */
+ AutoCaller thatCaller(aThat);
+ AssertComRCReturnVoid(thatCaller.rc());
+
+ /* even more sanity */
+ AutoAnyStateDependency adep(m->pParent);
+ AssertComRCReturnVoid(adep.rc());
+ /* Machine::copyFrom() may not be called when the VM is running */
+ AssertReturnVoid(!Global::IsOnline(adep.machineState()));
+
+ /* peer is not modified, lock it for reading (aThat is "master" so locked
+ * first) */
+ AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
+ AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
+
+#ifdef VBOX_WITH_USB
+
+ /* Note that we won't inform the USB proxy about new filters since the VM is
+ * not running when we are here and therefore no need to do so */
+
+ /* create private copies of all filters */
+ m->llDeviceFilters.backup();
+ m->llDeviceFilters->clear();
+ for (DeviceFilterList::const_iterator it = aThat->m->llDeviceFilters->begin();
+ it != aThat->m->llDeviceFilters->end();
+ ++it)
+ {
+ ComObjPtr<USBDeviceFilter> pFilter;
+ pFilter.createObject();
+ pFilter->initCopy(this, *it);
+ m->llDeviceFilters->push_back(pFilter);
+ }
+
+#endif /* VBOX_WITH_USB */
+}
+
+#ifdef VBOX_WITH_USB
+
+/**
+ * Called by setter methods of all USB device filters.
+ *
+ * @note Locks nothing.
+ */
+HRESULT USBDeviceFilters::onDeviceFilterChange(USBDeviceFilter *aFilter,
+ BOOL aActiveChanged /* = FALSE */)
+{
+ AutoCaller autoCaller(this);
+ AssertComRCReturnRC(autoCaller.rc());
+
+ /* we need the machine state */
+ AutoAnyStateDependency adep(m->pParent);
+ AssertComRCReturnRC(adep.rc());
+
+ /* nothing to do if the machine isn't running */
+ if (!Global::IsOnline(adep.machineState()))
+ return S_OK;
+
+ /* we don't modify our data fields -- no need to lock */
+
+ if ( aFilter->mInList
+ && m->pParent->isRegistered())
+ {
+ USBProxyService *pProxySvc = m->pHost->usbProxyService();
+ ComAssertRet(pProxySvc, E_FAIL);
+
+ if (aActiveChanged)
+ {
+ if (aFilter->getData().mRemote.isMatch(false))
+ {
+ /* insert/remove the filter from the proxy */
+ if (aFilter->getData().mActive)
+ {
+ ComAssertRet(aFilter->getId() == NULL, E_FAIL);
+ aFilter->getId() = pProxySvc->insertFilter(&aFilter->getData().mUSBFilter);
+ }
+ else
+ {
+ ComAssertRet(aFilter->getId() != NULL, E_FAIL);
+ pProxySvc->removeFilter(aFilter->getId());
+ aFilter->getId() = NULL;
+ }
+ }
+ }
+ else
+ {
+ if (aFilter->getData().mActive)
+ {
+ /* update the filter in the proxy */
+ ComAssertRet(aFilter->getId() != NULL, E_FAIL);
+ pProxySvc->removeFilter(aFilter->getId());
+ if (aFilter->getData().mRemote.isMatch(false))
+ {
+ aFilter->getId() = pProxySvc->insertFilter(&aFilter->getData().mUSBFilter);
+ }
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+/**
+ * Returns true if the given USB device matches to at least one of
+ * this controller's USB device filters.
+ *
+ * A HostUSBDevice specific version.
+ *
+ * @note Locks this object for reading.
+ */
+bool USBDeviceFilters::hasMatchingFilter(const ComObjPtr<HostUSBDevice> &aDevice, ULONG *aMaskedIfs)
+{
+ AutoCaller autoCaller(this);
+ AssertComRCReturn(autoCaller.rc(), false);
+
+ /* It is not possible to work with USB device if there is no USB controller present. */
+ if (!m->pParent->isUSBControllerPresent())
+ return false;
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ /* apply self filters */
+ for (DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
+ it != m->llDeviceFilters->end();
+ ++it)
+ {
+ AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS);
+ if (aDevice->isMatch((*it)->getData()))
+ {
+ *aMaskedIfs = (*it)->getData().mMaskedIfs;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Returns true if the given USB device matches to at least one of
+ * this controller's USB device filters.
+ *
+ * A generic version that accepts any IUSBDevice on input.
+ *
+ * @note
+ * This method MUST correlate with HostUSBDevice::isMatch()
+ * in the sense of the device matching logic.
+ *
+ * @note Locks this object for reading.
+ */
+bool USBDeviceFilters::hasMatchingFilter(IUSBDevice *aUSBDevice, ULONG *aMaskedIfs)
+{
+ LogFlowThisFuncEnter();
+
+ AutoCaller autoCaller(this);
+ AssertComRCReturn(autoCaller.rc(), false);
+
+ /* It is not possible to work with USB device if there is no USB controller present. */
+ if (!m->pParent->isUSBControllerPresent())
+ return false;
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ HRESULT rc = S_OK;
+
+ /* query fields */
+ USBFILTER dev;
+ USBFilterInit(&dev, USBFILTERTYPE_CAPTURE);
+
+ USHORT vendorId = 0;
+ rc = aUSBDevice->COMGETTER(VendorId)(&vendorId);
+ ComAssertComRCRet(rc, false);
+ ComAssertRet(vendorId, false);
+ int vrc = USBFilterSetNumExact(&dev, USBFILTERIDX_VENDOR_ID, vendorId, true); AssertRC(vrc);
+
+ USHORT productId = 0;
+ rc = aUSBDevice->COMGETTER(ProductId)(&productId);
+ ComAssertComRCRet(rc, false);
+ vrc = USBFilterSetNumExact(&dev, USBFILTERIDX_PRODUCT_ID, productId, true); AssertRC(vrc);
+
+ USHORT revision;
+ rc = aUSBDevice->COMGETTER(Revision)(&revision);
+ ComAssertComRCRet(rc, false);
+ vrc = USBFilterSetNumExact(&dev, USBFILTERIDX_DEVICE, revision, true); AssertRC(vrc);
+
+ Bstr manufacturer;
+ rc = aUSBDevice->COMGETTER(Manufacturer)(manufacturer.asOutParam());
+ ComAssertComRCRet(rc, false);
+ if (!manufacturer.isEmpty())
+ USBFilterSetStringExact(&dev, USBFILTERIDX_MANUFACTURER_STR, Utf8Str(manufacturer).c_str(), true);
+
+ Bstr product;
+ rc = aUSBDevice->COMGETTER(Product)(product.asOutParam());
+ ComAssertComRCRet(rc, false);
+ if (!product.isEmpty())
+ USBFilterSetStringExact(&dev, USBFILTERIDX_PRODUCT_STR, Utf8Str(product).c_str(), true);
+
+ Bstr serialNumber;
+ rc = aUSBDevice->COMGETTER(SerialNumber)(serialNumber.asOutParam());
+ ComAssertComRCRet(rc, false);
+ if (!serialNumber.isEmpty())
+ USBFilterSetStringExact(&dev, USBFILTERIDX_SERIAL_NUMBER_STR, Utf8Str(serialNumber).c_str(), true);
+
+ Bstr address;
+ rc = aUSBDevice->COMGETTER(Address)(address.asOutParam());
+ ComAssertComRCRet(rc, false);
+
+ USHORT port = 0;
+ rc = aUSBDevice->COMGETTER(Port)(&port);
+ ComAssertComRCRet(rc, false);
+ USBFilterSetNumExact(&dev, USBFILTERIDX_PORT, port, true);
+
+ BOOL remote = FALSE;
+ rc = aUSBDevice->COMGETTER(Remote)(&remote);
+ ComAssertComRCRet(rc, false);
+ ComAssertRet(remote == TRUE, false);
+
+ bool match = false;
+
+ /* apply self filters */
+ for (DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
+ it != m->llDeviceFilters->end();
+ ++it)
+ {
+ AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS);
+ const USBDeviceFilter::Data &aData = (*it)->getData();
+
+ if (!aData.mActive)
+ continue;
+ if (!aData.mRemote.isMatch(remote))
+ continue;
+ if (!USBFilterMatch(&aData.mUSBFilter, &dev))
+ continue;
+
+ match = true;
+ *aMaskedIfs = aData.mMaskedIfs;
+ break;
+ }
+
+ LogFlowThisFunc(("returns: %d\n", match));
+ LogFlowThisFuncLeave();
+
+ return match;
+}
+
+/**
+ * Notifies the proxy pProxySvc about all filters as requested by the
+ * @a aInsertFilters argument.
+ *
+ * @param aInsertFilters @c true to insert filters, @c false to remove.
+ *
+ * @note Locks this object for reading.
+ */
+HRESULT USBDeviceFilters::notifyProxy(bool aInsertFilters)
+{
+ LogFlowThisFunc(("aInsertFilters=%RTbool\n", aInsertFilters));
+
+ AutoCaller autoCaller(this);
+ AssertComRCReturn(autoCaller.rc(), false);
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ USBProxyService *pProxySvc = m->pHost->usbProxyService();
+ AssertReturn(pProxySvc, E_FAIL);
+
+ DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
+ while (it != m->llDeviceFilters->end())
+ {
+ USBDeviceFilter *pFilter = *it; /* resolve ambiguity (for ComPtr below) */
+
+ /* notify the proxy (only if the filter is active) */
+ if ( pFilter->getData().mActive
+ && pFilter->getData().mRemote.isMatch(false) /* and if the filter is NOT remote */
+ )
+ {
+ if (aInsertFilters)
+ {
+ AssertReturn(pFilter->getId() == NULL, E_FAIL);
+ pFilter->getId() = pProxySvc->insertFilter(&pFilter->getData().mUSBFilter);
+ }
+ else
+ {
+ /* It's possible that the given filter was not inserted the proxy
+ * when this method gets called (as a result of an early VM
+ * process crash for example. So, don't assert that ID != NULL. */
+ if (pFilter->getId() != NULL)
+ {
+ pProxySvc->removeFilter(pFilter->getId());
+ pFilter->getId() = NULL;
+ }
+ }
+ }
+ ++it;
+ }
+
+ return S_OK;
+}
+
+Machine* USBDeviceFilters::getMachine()
+{
+ return m->pParent;
+}
+
+#endif /* VBOX_WITH_USB */
+
+// private methods
+/////////////////////////////////////////////////////////////////////////////
+/* vi: set tabstop=4 shiftwidth=4 expandtab: */
diff --git a/src/VBox/Main/src-server/VFSExplorerImpl.cpp b/src/VBox/Main/src-server/VFSExplorerImpl.cpp
index e94b7225..9f50b667 100644
--- a/src/VBox/Main/src-server/VFSExplorerImpl.cpp
+++ b/src/VBox/Main/src-server/VFSExplorerImpl.cpp
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -622,7 +622,7 @@ STDMETHODIMP VFSExplorer::CdUp(IProgress **aProgress)
return Cd(Bstr(strUpPath).raw(), aProgress);
}
-STDMETHODIMP VFSExplorer::EntryList(ComSafeArrayOut(BSTR, aNames), ComSafeArrayOut(VFSFileType_T, aTypes), ComSafeArrayOut(ULONG, aSizes), ComSafeArrayOut(ULONG, aModes))
+STDMETHODIMP VFSExplorer::EntryList(ComSafeArrayOut(BSTR, aNames), ComSafeArrayOut(VFSFileType_T, aTypes), ComSafeArrayOut(LONG64, aSizes), ComSafeArrayOut(ULONG, aModes))
{
if (ComSafeArrayOutIsNull(aNames) ||
ComSafeArrayOutIsNull(aTypes))
@@ -635,7 +635,7 @@ STDMETHODIMP VFSExplorer::EntryList(ComSafeArrayOut(BSTR, aNames), ComSafeArrayO
com::SafeArray<BSTR> sfaNames(m->entryList.size());
com::SafeArray<ULONG> sfaTypes(m->entryList.size());
- com::SafeArray<ULONG> sfaSizes(m->entryList.size());
+ com::SafeArray<LONG64> sfaSizes(m->entryList.size());
com::SafeArray<ULONG> sfaModes(m->entryList.size());
std::list<VFSExplorer::Data::DirEntry>::const_iterator it;
diff --git a/src/VBox/Main/src-server/VRDEServerImpl.cpp b/src/VBox/Main/src-server/VRDEServerImpl.cpp
index 5862545a..a717affe 100644
--- a/src/VBox/Main/src-server/VRDEServerImpl.cpp
+++ b/src/VBox/Main/src-server/VRDEServerImpl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -29,6 +29,7 @@
#include <VBox/err.h>
#include <VBox/sup.h>
+#include <VBox/com/array.h>
#include <VBox/RemoteDesktop/VRDE.h>
@@ -72,7 +73,7 @@ void VRDEServer::FinalRelease()
*
* @param aParent Handle of the parent object.
*/
-HRESULT VRDEServer::init (Machine *aParent)
+HRESULT VRDEServer::init(Machine *aParent)
{
LogFlowThisFunc(("aParent=%p\n", aParent));
@@ -111,7 +112,7 @@ HRESULT VRDEServer::init (Machine *aParent)
*
* @note Locks @a aThat object for reading.
*/
-HRESULT VRDEServer::init (Machine *aParent, VRDEServer *aThat)
+HRESULT VRDEServer::init(Machine *aParent, VRDEServer *aThat)
{
LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
@@ -124,11 +125,11 @@ HRESULT VRDEServer::init (Machine *aParent, VRDEServer *aThat)
unconst(mParent) = aParent;
unconst(mPeer) = aThat;
- AutoCaller thatCaller (aThat);
+ AutoCaller thatCaller(aThat);
AssertComRCReturnRC(thatCaller.rc());
AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
- mData.share (aThat->mData);
+ mData.share(aThat->mData);
/* Confirm a successful initialization */
autoInitSpan.setSucceeded();
@@ -143,7 +144,7 @@ HRESULT VRDEServer::init (Machine *aParent, VRDEServer *aThat)
*
* @note Locks @a aThat object for reading.
*/
-HRESULT VRDEServer::initCopy (Machine *aParent, VRDEServer *aThat)
+HRESULT VRDEServer::initCopy(Machine *aParent, VRDEServer *aThat)
{
LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
@@ -156,11 +157,11 @@ HRESULT VRDEServer::initCopy (Machine *aParent, VRDEServer *aThat)
unconst(mParent) = aParent;
/* mPeer is left null */
- AutoCaller thatCaller (aThat);
+ AutoCaller thatCaller(aThat);
AssertComRCReturnRC(thatCaller.rc());
AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
- mData.attachCopy (aThat->mData);
+ mData.attachCopy(aThat->mData);
/* Confirm a successful initialization */
autoInitSpan.setSucceeded();
@@ -245,7 +246,7 @@ HRESULT VRDEServer::saveSettings(settings::VRDESettings &data)
// IVRDEServer properties
/////////////////////////////////////////////////////////////////////////////
-STDMETHODIMP VRDEServer::COMGETTER(Enabled) (BOOL *aEnabled)
+STDMETHODIMP VRDEServer::COMGETTER(Enabled)(BOOL *aEnabled)
{
CheckComArgOutPointerValid(aEnabled);
@@ -257,17 +258,19 @@ STDMETHODIMP VRDEServer::COMGETTER(Enabled) (BOOL *aEnabled)
return S_OK;
}
-STDMETHODIMP VRDEServer::COMSETTER(Enabled) (BOOL aEnabled)
+STDMETHODIMP VRDEServer::COMSETTER(Enabled)(BOOL aEnabled)
{
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
/* the machine can also be in saved state for this property to change */
- AutoMutableOrSavedStateDependency adep (mParent);
+ AutoMutableOrSavedStateDependency adep(mParent);
if (FAILED(adep.rc())) return adep.rc();
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+ HRESULT rc = S_OK;
+
if (mData->mEnabled != aEnabled)
{
mData.backup();
@@ -283,10 +286,10 @@ STDMETHODIMP VRDEServer::COMSETTER(Enabled) (BOOL aEnabled)
/* Avoid deadlock when onVRDEServerChange eventually calls SetExtraData. */
adep.release();
- mParent->onVRDEServerChange(/* aRestart */ TRUE);
+ rc = mParent->onVRDEServerChange(/* aRestart */ TRUE);
}
- return S_OK;
+ return rc;
}
static int portParseNumber(uint16_t *pu16Port, const char *pszStart, const char *pszEnd)
@@ -373,15 +376,15 @@ static int vrdpServerVerifyPortsString(Bstr ports)
return VINF_SUCCESS;
}
-STDMETHODIMP VRDEServer::SetVRDEProperty (IN_BSTR aKey, IN_BSTR aValue)
+STDMETHODIMP VRDEServer::SetVRDEProperty(IN_BSTR aKey, IN_BSTR aValue)
{
LogFlowThisFunc(("\n"));
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
- /* The machine needs to be mutable. */
- AutoMutableStateDependency adep(mParent);
+ /* the machine can also be in saved state for this property to change */
+ AutoMutableOrSavedStateDependency adep(mParent);
if (FAILED(adep.rc())) return adep.rc();
Bstr key = aKey;
@@ -460,7 +463,7 @@ STDMETHODIMP VRDEServer::SetVRDEProperty (IN_BSTR aKey, IN_BSTR aValue)
return S_OK;
}
-STDMETHODIMP VRDEServer::GetVRDEProperty (IN_BSTR aKey, BSTR *aValue)
+STDMETHODIMP VRDEServer::GetVRDEProperty(IN_BSTR aKey, BSTR *aValue)
{
CheckComArgOutPointerValid(aValue);
@@ -627,7 +630,7 @@ STDMETHODIMP VRDEServer::COMGETTER(VRDEProperties)(ComSafeArrayOut(BSTR, aProper
return S_OK;
}
-STDMETHODIMP VRDEServer::COMGETTER(AuthType) (AuthType_T *aType)
+STDMETHODIMP VRDEServer::COMGETTER(AuthType)(AuthType_T *aType)
{
CheckComArgOutPointerValid(aType);
@@ -641,13 +644,13 @@ STDMETHODIMP VRDEServer::COMGETTER(AuthType) (AuthType_T *aType)
return S_OK;
}
-STDMETHODIMP VRDEServer::COMSETTER(AuthType) (AuthType_T aType)
+STDMETHODIMP VRDEServer::COMSETTER(AuthType)(AuthType_T aType)
{
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
- /* the machine needs to be mutable */
- AutoMutableStateDependency adep(mParent);
+ /* the machine can also be in saved state for this property to change */
+ AutoMutableOrSavedStateDependency adep(mParent);
if (FAILED(adep.rc())) return adep.rc();
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
@@ -670,7 +673,7 @@ STDMETHODIMP VRDEServer::COMSETTER(AuthType) (AuthType_T aType)
return S_OK;
}
-STDMETHODIMP VRDEServer::COMGETTER(AuthTimeout) (ULONG *aTimeout)
+STDMETHODIMP VRDEServer::COMGETTER(AuthTimeout)(ULONG *aTimeout)
{
CheckComArgOutPointerValid(aTimeout);
@@ -684,13 +687,13 @@ STDMETHODIMP VRDEServer::COMGETTER(AuthTimeout) (ULONG *aTimeout)
return S_OK;
}
-STDMETHODIMP VRDEServer::COMSETTER(AuthTimeout) (ULONG aTimeout)
+STDMETHODIMP VRDEServer::COMSETTER(AuthTimeout)(ULONG aTimeout)
{
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
- /* the machine needs to be mutable */
- AutoMutableStateDependency adep(mParent);
+ /* the machine can also be in saved state for this property to change */
+ AutoMutableOrSavedStateDependency adep(mParent);
if (FAILED(adep.rc())) return adep.rc();
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
@@ -717,7 +720,7 @@ STDMETHODIMP VRDEServer::COMSETTER(AuthTimeout) (ULONG aTimeout)
return S_OK;
}
-STDMETHODIMP VRDEServer::COMGETTER(AuthLibrary) (BSTR *aLibrary)
+STDMETHODIMP VRDEServer::COMGETTER(AuthLibrary)(BSTR *aLibrary)
{
CheckComArgOutPointerValid(aLibrary);
@@ -748,13 +751,13 @@ STDMETHODIMP VRDEServer::COMGETTER(AuthLibrary) (BSTR *aLibrary)
return S_OK;
}
-STDMETHODIMP VRDEServer::COMSETTER(AuthLibrary) (IN_BSTR aLibrary)
+STDMETHODIMP VRDEServer::COMSETTER(AuthLibrary)(IN_BSTR aLibrary)
{
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
- /* the machine needs to be mutable */
- AutoMutableStateDependency adep(mParent);
+ /* the machine can also be in saved state for this property to change */
+ AutoMutableOrSavedStateDependency adep(mParent);
if (FAILED(adep.rc())) return adep.rc();
Bstr bstrLibrary(aLibrary);
@@ -779,8 +782,7 @@ STDMETHODIMP VRDEServer::COMSETTER(AuthLibrary) (IN_BSTR aLibrary)
return S_OK;
}
-STDMETHODIMP VRDEServer::COMGETTER(AllowMultiConnection) (
- BOOL *aAllowMultiConnection)
+STDMETHODIMP VRDEServer::COMGETTER(AllowMultiConnection)(BOOL *aAllowMultiConnection)
{
CheckComArgOutPointerValid(aAllowMultiConnection);
@@ -794,14 +796,13 @@ STDMETHODIMP VRDEServer::COMGETTER(AllowMultiConnection) (
return S_OK;
}
-STDMETHODIMP VRDEServer::COMSETTER(AllowMultiConnection) (
- BOOL aAllowMultiConnection)
+STDMETHODIMP VRDEServer::COMSETTER(AllowMultiConnection)(BOOL aAllowMultiConnection)
{
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
- /* the machine needs to be mutable */
- AutoMutableStateDependency adep(mParent);
+ /* the machine can also be in saved state for this property to change */
+ AutoMutableOrSavedStateDependency adep(mParent);
if (FAILED(adep.rc())) return adep.rc();
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
@@ -824,8 +825,7 @@ STDMETHODIMP VRDEServer::COMSETTER(AllowMultiConnection) (
return S_OK;
}
-STDMETHODIMP VRDEServer::COMGETTER(ReuseSingleConnection) (
- BOOL *aReuseSingleConnection)
+STDMETHODIMP VRDEServer::COMGETTER(ReuseSingleConnection)(BOOL *aReuseSingleConnection)
{
CheckComArgOutPointerValid(aReuseSingleConnection);
@@ -839,14 +839,13 @@ STDMETHODIMP VRDEServer::COMGETTER(ReuseSingleConnection) (
return S_OK;
}
-STDMETHODIMP VRDEServer::COMSETTER(ReuseSingleConnection) (
- BOOL aReuseSingleConnection)
+STDMETHODIMP VRDEServer::COMSETTER(ReuseSingleConnection)(BOOL aReuseSingleConnection)
{
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
- /* the machine needs to be mutable */
- AutoMutableStateDependency adep(mParent);
+ /* the machine can also be in saved state for this property to change */
+ AutoMutableOrSavedStateDependency adep(mParent);
if (FAILED(adep.rc())) return adep.rc();
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
@@ -869,7 +868,7 @@ STDMETHODIMP VRDEServer::COMSETTER(ReuseSingleConnection) (
return S_OK;
}
-STDMETHODIMP VRDEServer::COMGETTER(VRDEExtPack) (BSTR *aExtPack)
+STDMETHODIMP VRDEServer::COMGETTER(VRDEExtPack)(BSTR *aExtPack)
{
CheckComArgOutPointerValid(aExtPack);
@@ -919,8 +918,8 @@ STDMETHODIMP VRDEServer::COMSETTER(VRDEExtPack)(IN_BSTR aExtPack)
HRESULT hrc = autoCaller.rc();
if (SUCCEEDED(hrc))
{
- /* the machine needs to be mutable */
- AutoMutableStateDependency adep(mParent);
+ /* the machine can also be in saved state for this property to change */
+ AutoMutableOrSavedStateDependency adep(mParent);
hrc = adep.rc();
if (SUCCEEDED(hrc))
{
@@ -994,11 +993,11 @@ void VRDEServer::commit()
{
/* sanity */
AutoCaller autoCaller(this);
- AssertComRCReturnVoid (autoCaller.rc());
+ AssertComRCReturnVoid(autoCaller.rc());
/* sanity too */
- AutoCaller peerCaller (mPeer);
- AssertComRCReturnVoid (peerCaller.rc());
+ AutoCaller peerCaller(mPeer);
+ AssertComRCReturnVoid(peerCaller.rc());
/* lock both for writing since we modify both (mPeer is "master" so locked
* first) */
@@ -1010,7 +1009,7 @@ void VRDEServer::commit()
if (mPeer)
{
/* attach new data to the peer and reshare it */
- mPeer->mData.attach (mData);
+ mPeer->mData.attach(mData);
}
}
}
@@ -1019,17 +1018,17 @@ void VRDEServer::commit()
* @note Locks this object for writing, together with the peer object
* represented by @a aThat (locked for reading).
*/
-void VRDEServer::copyFrom (VRDEServer *aThat)
+void VRDEServer::copyFrom(VRDEServer *aThat)
{
- AssertReturnVoid (aThat != NULL);
+ AssertReturnVoid(aThat != NULL);
/* sanity */
AutoCaller autoCaller(this);
- AssertComRCReturnVoid (autoCaller.rc());
+ AssertComRCReturnVoid(autoCaller.rc());
/* sanity too */
- AutoCaller thatCaller (aThat);
- AssertComRCReturnVoid (thatCaller.rc());
+ AutoCaller thatCaller(aThat);
+ AssertComRCReturnVoid(thatCaller.rc());
/* peer is not modified, lock it for reading (aThat is "master" so locked
* first) */
@@ -1037,6 +1036,6 @@ void VRDEServer::copyFrom (VRDEServer *aThat)
AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
/* this will back up current data */
- mData.assignCopy (aThat->mData);
+ mData.assignCopy(aThat->mData);
}
/* vi: set tabstop=4 shiftwidth=4 expandtab: */
diff --git a/src/VBox/Main/src-server/VirtualBoxImpl.cpp b/src/VBox/Main/src-server/VirtualBoxImpl.cpp
index 64135154..7c319236 100644
--- a/src/VBox/Main/src-server/VirtualBoxImpl.cpp
+++ b/src/VBox/Main/src-server/VirtualBoxImpl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -35,6 +35,7 @@
#include <VBox/com/com.h>
#include <VBox/com/array.h>
#include "VBox/com/EventQueue.h"
+#include "VBox/com/MultiResult.h"
#include <VBox/err.h>
#include <VBox/param.h>
@@ -60,8 +61,9 @@
#include "USBControllerImpl.h"
#include "SystemPropertiesImpl.h"
#include "GuestOSTypeImpl.h"
-#include "DHCPServerRunner.h"
+#include "NetworkServiceRunner.h"
#include "DHCPServerImpl.h"
+#include "NATNetworkImpl.h"
#ifdef VBOX_WITH_RESOURCE_USAGE_API
# include "PerformanceImpl.h"
#endif /* VBOX_WITH_RESOURCE_USAGE_API */
@@ -71,10 +73,10 @@
# include "ExtPackManagerImpl.h"
#endif
#include "AutostartDb.h"
+#include "ClientWatcher.h"
#include "AutoCaller.h"
#include "Logging.h"
-#include "objectslist.h"
#ifdef RT_OS_WINDOWS
# include "win/svchlp.h"
@@ -110,12 +112,11 @@ Bstr VirtualBox::sPackageType;
// static
Bstr VirtualBox::sAPIVersion;
-#ifdef VBOX_WITH_SYS_V_IPC_SESSION_WATCHER
-/** Table for adaptive timeouts in the client watcher. The counter starts at
- * the maximum value and decreases to 0. */
-static const RTMSINTERVAL s_updateAdaptTimeouts[] = { 500, 200, 100, 50, 20, 10, 5 };
-#endif
+// static
+std::map<Bstr, int> VirtualBox::sNatNetworkNameToRefCount;
+// static leaked (todo: find better place to free it.)
+RWLockHandle *VirtualBox::spMtxNatNetworkNameToRefCountLock;
////////////////////////////////////////////////////////////////////////////////
//
// CallbackEvent class
@@ -163,24 +164,11 @@ protected:
//
////////////////////////////////////////////////////////////////////////////////
-#if defined(RT_OS_WINDOWS)
- #define UPDATEREQARG NULL
- #define UPDATEREQTYPE HANDLE
-#elif defined(RT_OS_OS2)
- #define UPDATEREQARG NIL_RTSEMEVENT
- #define UPDATEREQTYPE RTSEMEVENT
-#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
- #define UPDATEREQARG
- #define UPDATEREQTYPE RTSEMEVENT
-#else
-# error "Port me!"
-#endif
-
-typedef ObjectsList<Machine> MachinesOList;
typedef ObjectsList<Medium> MediaOList;
typedef ObjectsList<GuestOSType> GuestOSTypesOList;
typedef ObjectsList<SharedFolder> SharedFoldersOList;
typedef ObjectsList<DHCPServer> DHCPServersOList;
+typedef ObjectsList<NATNetwork> NATNetworksOList;
typedef std::map<Guid, ComPtr<IProgress> > ProgressMap;
typedef std::map<Guid, ComObjPtr<Medium> > HardDiskMap;
@@ -208,9 +196,10 @@ struct VirtualBox::Data
allSharedFolders(lockSharedFolders),
lockDHCPServers(LOCKCLASS_LISTOFOTHEROBJECTS),
allDHCPServers(lockDHCPServers),
+ lockNATNetworks(LOCKCLASS_LISTOFOTHEROBJECTS),
+ allNATNetworks(lockNATNetworks),
mtxProgressOperations(LOCKCLASS_PROGRESSLIST),
- updateReq(UPDATEREQARG),
- threadClientWatcher(NIL_RTTHREAD),
+ pClientWatcher(NULL),
threadAsyncEvent(NIL_RTTHREAD),
pAsyncEventQ(NULL),
pAutostartDb(NULL),
@@ -286,17 +275,13 @@ struct VirtualBox::Data
RWLockHandle lockDHCPServers;
DHCPServersOList allDHCPServers;
+ RWLockHandle lockNATNetworks;
+ NATNetworksOList allNATNetworks;
+
RWLockHandle mtxProgressOperations;
ProgressMap mapProgressOperations;
- // the following are data for the client watcher thread
- const UPDATEREQTYPE updateReq;
-#ifdef VBOX_WITH_SYS_V_IPC_SESSION_WATCHER
- uint8_t updateAdaptCtr;
-#endif
- const RTTHREAD threadClientWatcher;
- typedef std::list<RTPROCESS> ProcessList;
- ProcessList llProcesses;
+ ClientWatcher * const pClientWatcher;
// the following are data for the async event thread
const RTTHREAD threadAsyncEvent;
@@ -385,6 +370,9 @@ HRESULT VirtualBox::init()
sPackageType = VBOX_PACKAGE_STRING;
if (sAPIVersion.isEmpty())
sAPIVersion = VBOX_API_VERSION_STRING;
+ if (!spMtxNatNetworkNameToRefCountLock)
+ spMtxNatNetworkNameToRefCountLock = new RWLockHandle(LOCKCLASS_VIRTUALBOXOBJECT);
+
LogFlowThisFunc(("Version: %ls, Package: %ls, API Version: %ls\n", sVersion.raw(), sPackageType.raw(), sAPIVersion.raw()));
/* Get the VirtualBox home directory. */
@@ -485,7 +473,7 @@ HRESULT VirtualBox::init()
dumpAllBackRefs();
#endif
- /* net services */
+ /* net services - dhcp services */
for (settings::DHCPServersList::const_iterator it = m->pMainConfigFile->llDhcpServers.begin();
it != m->pMainConfigFile->llDhcpServers.end();
++it)
@@ -501,9 +489,27 @@ HRESULT VirtualBox::init()
if (FAILED(rc)) throw rc;
}
+ /* net services - nat networks */
+ for (settings::NATNetworksList::const_iterator it = m->pMainConfigFile->llNATNetworks.begin();
+ it != m->pMainConfigFile->llNATNetworks.end();
+ ++it)
+ {
+ const settings::NATNetwork &net = *it;
+
+ ComObjPtr<NATNetwork> pNATNetwork;
+ if (SUCCEEDED(rc = pNATNetwork.createObject()))
+ {
+ rc = pNATNetwork->init(this, net);
+ AssertComRCReturnRC(rc);
+ }
+
+ rc = registerNATNetwork(pNATNetwork, false /* aSaveRegistry */);
+ AssertComRCReturnRC(rc);
+ }
+
/* events */
if (SUCCEEDED(rc = unconst(m->pEventSource).createObject()))
- rc = m->pEventSource->init(static_cast<IVirtualBox*>(this));
+ rc = m->pEventSource->init();
if (FAILED(rc)) throw rc;
#ifdef VBOX_WITH_EXTPACK
@@ -527,27 +533,21 @@ HRESULT VirtualBox::init()
if (SUCCEEDED(rc))
{
- /* start the client watcher thread */
-#if defined(RT_OS_WINDOWS)
- unconst(m->updateReq) = ::CreateEvent(NULL, FALSE, FALSE, NULL);
-#elif defined(RT_OS_OS2)
- RTSemEventCreate(&unconst(m->updateReq));
-#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
- RTSemEventCreate(&unconst(m->updateReq));
- ASMAtomicUoWriteU8(&m->updateAdaptCtr, 0);
-#else
-# error "Port me!"
-#endif
- int vrc = RTThreadCreate(&unconst(m->threadClientWatcher),
- ClientWatcher,
- (void *)this,
- 0,
- RTTHREADTYPE_MAIN_WORKER,
- RTTHREADFLAGS_WAITABLE,
- "Watcher");
- ComAssertRC(vrc);
- if (RT_FAILURE(vrc))
- rc = E_FAIL;
+ /* set up client monitoring */
+ try
+ {
+ unconst(m->pClientWatcher) = new ClientWatcher(this);
+ if (!m->pClientWatcher->isReady())
+ {
+ delete m->pClientWatcher;
+ unconst(m->pClientWatcher) = NULL;
+ rc = E_FAIL;
+ }
+ }
+ catch (std::bad_alloc &)
+ {
+ rc = E_OUTOFMEMORY;
+ }
}
if (SUCCEEDED(rc))
@@ -807,41 +807,20 @@ void VirtualBox::uninit()
LogFlowThisFunc(("Releasing event source...\n"));
if (m->pEventSource)
{
- // we don't perform uninit() as it's possible that some pending event refers to this source
+ // Must uninit the event source here, because it makes no sense that
+ // it survives longer than the base object. If someone gets an event
+ // with such an event source then that's life and it has to be dealt
+ // with appropriately on the API client side.
+ m->pEventSource->uninit();
unconst(m->pEventSource).setNull();
}
LogFlowThisFunc(("Terminating the client watcher...\n"));
- if (m->threadClientWatcher != NIL_RTTHREAD)
- {
- /* signal the client watcher thread */
- updateClientWatcher();
- /* wait for the termination */
- RTThreadWait(m->threadClientWatcher, RT_INDEFINITE_WAIT, NULL);
- unconst(m->threadClientWatcher) = NIL_RTTHREAD;
- }
- m->llProcesses.clear();
-#if defined(RT_OS_WINDOWS)
- if (m->updateReq != NULL)
- {
- ::CloseHandle(m->updateReq);
- unconst(m->updateReq) = NULL;
- }
-#elif defined(RT_OS_OS2)
- if (m->updateReq != NIL_RTSEMEVENT)
+ if (m->pClientWatcher)
{
- RTSemEventDestroy(m->updateReq);
- unconst(m->updateReq) = NIL_RTSEMEVENT;
+ delete m->pClientWatcher;
+ unconst(m->pClientWatcher) = NULL;
}
-#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
- if (m->updateReq != NIL_RTSEMEVENT)
- {
- RTSemEventDestroy(m->updateReq);
- unconst(m->updateReq) = NIL_RTSEMEVENT;
- }
-#else
-# error "Port me!"
-#endif
delete m->pAutostartDb;
@@ -1129,6 +1108,7 @@ VirtualBox::COMGETTER(PerformanceCollector)(IPerformanceCollector **aPerformance
return S_OK;
#else /* !VBOX_WITH_RESOURCE_USAGE_API */
+ NOREF(aPerformanceCollector);
ReturnComNotImplemented();
#endif /* !VBOX_WITH_RESOURCE_USAGE_API */
}
@@ -1148,6 +1128,31 @@ VirtualBox::COMGETTER(DHCPServers)(ComSafeArrayOut(IDHCPServer *, aDHCPServers))
return S_OK;
}
+
+STDMETHODIMP
+VirtualBox::COMGETTER(NATNetworks)(ComSafeArrayOut(INATNetwork *, aNATNetworks))
+{
+#ifdef VBOX_WITH_NAT_SERVICE
+ CheckComArgOutSafeArrayPointerValid(aNATNetworks);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoReadLock al(m->allNATNetworks.getLockHandle() COMMA_LOCKVAL_SRC_POS);
+ SafeIfaceArray<INATNetwork> nets(m->allNATNetworks.getList());
+ nets.detachTo(ComSafeArrayOutArg(aNATNetworks));
+
+ return S_OK;
+#else
+ NOREF(aNATNetworks);
+# ifndef RT_OS_WINDOWS
+ NOREF(aNATNetworksSize);
+# endif
+ return E_NOTIMPL;
+#endif
+}
+
+
STDMETHODIMP
VirtualBox::COMGETTER(EventSource)(IEventSource ** aEventSource)
{
@@ -1452,8 +1457,16 @@ STDMETHODIMP VirtualBox::ComposeMachineFilename(IN_BSTR aName,
pcszNext += strFlag.length() + 1;
}
}
- if (id.isEmpty())
+
+ if (id.isZero())
fDirectoryIncludesUUID = false;
+ else if (!id.isValid())
+ {
+ /* do something else */
+ return setError(E_INVALIDARG,
+ tr("'%ls' is not a valid Guid"),
+ id.toStringCurly().c_str());
+ }
Utf8Str strGroup(aGroup);
if (strGroup.isEmpty())
@@ -1514,13 +1527,13 @@ void sanitiseMachineFilename(Utf8Str &strName)
* *nix, or be otherwise difficult for shells to handle (I would have
* preferred to remove the space and brackets too). We also remove all
* characters which need UTF-16 surrogate pairs for Windows's benefit. */
-#ifdef RT_STRICT
RTUNICP aCpSet[] =
{ ' ', ' ', '(', ')', '-', '.', '0', '9', 'A', 'Z', 'a', 'z', '_', '_',
0xa0, 0xd7af, '\0' };
-#endif
char *pszName = strName.mutableRaw();
- Assert(RTStrPurgeComplementSet(pszName, aCpSet, '_') >= 0);
+ int cReplacements = RTStrPurgeComplementSet(pszName, aCpSet, '_');
+ Assert(cReplacements >= 0);
+ NOREF(cReplacements);
/* No leading dot or dash. */
if (pszName[0] == '.' || pszName[0] == '-')
pszName[0] = '_';
@@ -1648,8 +1661,15 @@ STDMETHODIMP VirtualBox::CreateMachine(IN_BSTR aSettingsFile,
}
}
/* Create UUID if none was specified. */
- if (id.isEmpty())
+ if (id.isZero())
id.create();
+ else if (!id.isValid())
+ {
+ /* do something else */
+ return setError(E_INVALIDARG,
+ tr("'%ls' is not a valid Guid"),
+ id.toStringCurly().c_str());
+ }
/* NULL settings file means compose automatically */
Bstr bstrSettingsFile(aSettingsFile);
@@ -1779,7 +1799,8 @@ STDMETHODIMP VirtualBox::FindMachine(IN_BSTR aNameOrId, IMachine **aMachine)
ComObjPtr<Machine> pMachineFound;
Guid id(aNameOrId);
- if (!id.isEmpty())
+ if (id.isValid() && !id.isZero())
+
rc = findMachine(id,
true /* fPermitInaccessible */,
true /* setError */,
@@ -1939,6 +1960,7 @@ STDMETHODIMP VirtualBox::OpenMedium(IN_BSTR aLocation,
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
+ Guid id(aLocation);
ComObjPtr<Medium> pMedium;
// have to get write lock as the whole find/update sequence must be done
@@ -1951,18 +1973,22 @@ STDMETHODIMP VirtualBox::OpenMedium(IN_BSTR aLocation,
switch (deviceType)
{
case DeviceType_HardDisk:
- rc = findHardDiskByLocation(aLocation,
- false, /* aSetError */
- &pMedium);
+ if (id.isValid() && !id.isZero())
+ rc = findHardDiskById(id, false /* setError */, &pMedium);
+ else
+ rc = findHardDiskByLocation(aLocation,
+ false, /* aSetError */
+ &pMedium);
break;
case DeviceType_Floppy:
case DeviceType_DVD:
- rc = findDVDOrFloppyImage(deviceType,
- NULL, /* guid */
- aLocation,
- false, /* aSetError */
- &pMedium);
+ if (id.isValid() && !id.isZero())
+ rc = findDVDOrFloppyImage(deviceType, &id, Utf8Str::Empty,
+ false /* setError */, &pMedium);
+ else
+ rc = findDVDOrFloppyImage(deviceType, NULL, aLocation,
+ false /* setError */, &pMedium);
// enforce read-only for DVDs even if caller specified ReadWrite
if (deviceType == DeviceType_DVD)
@@ -1973,7 +1999,6 @@ STDMETHODIMP VirtualBox::OpenMedium(IN_BSTR aLocation,
return setError(E_INVALIDARG, "Device type must be HardDisk, DVD or Floppy %d", deviceType);
}
-
if (pMedium.isNull())
{
pMedium.createObject();
@@ -2768,7 +2793,7 @@ VirtualBox::SVCHelperClientThread(RTTHREAD aThread, void *aUser)
#endif /* RT_OS_WINDOWS */
/**
- * Sends a signal to the client watcher thread to rescan the set of machines
+ * Sends a signal to the client watcher to rescan the set of machines
* that have open sessions.
*
* @note Doesn't lock anything.
@@ -2778,35 +2803,23 @@ void VirtualBox::updateClientWatcher()
AutoCaller autoCaller(this);
AssertComRCReturnVoid(autoCaller.rc());
- AssertReturnVoid(m->threadClientWatcher != NIL_RTTHREAD);
-
- /* sent an update request */
-#if defined(RT_OS_WINDOWS)
- ::SetEvent(m->updateReq);
-#elif defined(RT_OS_OS2)
- RTSemEventSignal(m->updateReq);
-#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
- ASMAtomicUoWriteU8(&m->updateAdaptCtr, RT_ELEMENTS(s_updateAdaptTimeouts) - 1);
- RTSemEventSignal(m->updateReq);
-#else
-# error "Port me!"
-#endif
+ AssertPtrReturnVoid(m->pClientWatcher);
+ m->pClientWatcher->update();
}
/**
* Adds the given child process ID to the list of processes to be reaped.
* This call should be followed by #updateClientWatcher() to take the effect.
+ *
+ * @note Doesn't lock anything.
*/
void VirtualBox::addProcessToReap(RTPROCESS pid)
{
AutoCaller autoCaller(this);
AssertComRCReturnVoid(autoCaller.rc());
- /// @todo (dmik) Win32?
-#ifndef RT_OS_WINDOWS
- AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
- m->llProcesses.push_back(pid);
-#endif
+ AssertPtrReturnVoid(m->pClientWatcher);
+ m->pClientWatcher->addProcess(pid);
}
/** Event for onMachineStateChange(), onMachineDataChange(), onMachineRegistered() */
@@ -2977,8 +2990,8 @@ struct SnapshotEvent : public VirtualBox::CallbackEvent
virtual HRESULT prepareEventDesc(IEventSource* aSource, VBoxEventDesc& aEvDesc)
{
- return aEvDesc.init(aSource, VBoxEventType_OnSnapshotTaken,
- machineId.toUtf16().raw(), snapshotId.toUtf16().raw());
+ return aEvDesc.init(aSource, mWhat, machineId.toUtf16().raw(),
+ snapshotId.toUtf16().raw());
}
Guid machineId;
@@ -3043,65 +3056,108 @@ void VirtualBox::onGuestPropertyChange(const Guid &aMachineId, IN_BSTR aName,
postEvent(new GuestPropertyEvent(this, aMachineId, aName, aValue, aFlags));
}
-/** Event for onMachineUninit(), this is not a CallbackEvent */
-class MachineUninitEvent : public Event
+/**
+ * @note Doesn't lock any object.
+ */
+void VirtualBox::onNatRedirectChange(const Guid &aMachineId, ULONG ulSlot, bool fRemove, IN_BSTR aName,
+ NATProtocol_T aProto, IN_BSTR aHostIp, uint16_t aHostPort,
+ IN_BSTR aGuestIp, uint16_t aGuestPort)
{
-public:
+ fireNATRedirectEvent(m->pEventSource, aMachineId.toUtf16().raw(), ulSlot, fRemove, aName, aProto, aHostIp,
+ aHostPort, aGuestIp, aGuestPort);
+}
- MachineUninitEvent(VirtualBox *aVirtualBox, Machine *aMachine)
- : mVirtualBox(aVirtualBox), mMachine(aMachine)
- {
- Assert(aVirtualBox);
- Assert(aMachine);
- }
+void VirtualBox::onNATNetworkChange(IN_BSTR aName)
+{
+ fireNATNetworkChangedEvent(m->pEventSource, aName);
+}
- void *handler()
- {
-#ifdef VBOX_WITH_RESOURCE_USAGE_API
- /* Handle unregistering metrics here, as it is not vital to get
- * it done immediately. It reduces the number of locks needed and
- * the lock contention in SessionMachine::uninit. */
- {
- AutoWriteLock mLock(mMachine COMMA_LOCKVAL_SRC_POS);
- mMachine->unregisterMetrics(mVirtualBox->performanceCollector(), mMachine);
- }
-#endif /* VBOX_WITH_RESOURCE_USAGE_API */
+void VirtualBox::onNATNetworkStartStop(IN_BSTR aName, BOOL fStart)
+{
+ fireNATNetworkStartStopEvent(m->pEventSource, aName, fStart);
+}
+void VirtualBox::onNATNetworkSetting(IN_BSTR aNetworkName, BOOL aEnabled,
+ IN_BSTR aNetwork, IN_BSTR aGateway,
+ BOOL aAdvertiseDefaultIpv6RouteEnabled,
+ BOOL fNeedDhcpServer)
+{
+ fireNATNetworkSettingEvent(m->pEventSource, aNetworkName, aEnabled,
+ aNetwork, aGateway,
+ aAdvertiseDefaultIpv6RouteEnabled, fNeedDhcpServer);
+}
- return NULL;
- }
+void VirtualBox::onNATNetworkPortForward(IN_BSTR aNetworkName, BOOL create, BOOL fIpv6,
+ IN_BSTR aRuleName, NATProtocol_T proto,
+ IN_BSTR aHostIp, LONG aHostPort,
+ IN_BSTR aGuestIp, LONG aGuestPort)
+{
+ fireNATNetworkPortForwardEvent(m->pEventSource, aNetworkName, create,
+ fIpv6, aRuleName, proto,
+ aHostIp, aHostPort,
+ aGuestIp, aGuestPort);
+}
-private:
- /**
- * Note that this is a weak ref -- the CallbackEvent handler thread
- * is bound to the lifetime of the VirtualBox instance, so it's safe.
- */
- VirtualBox *mVirtualBox;
+void VirtualBox::onHostNameResolutionConfigurationChange()
+{
+ if (m->pEventSource)
+ fireHostNameResolutionConfigurationChangeEvent(m->pEventSource);
+}
- /** Reference to the machine object. */
- ComObjPtr<Machine> mMachine;
-};
-/**
- * Trigger internal event. This isn't meant to be signalled to clients.
- * @note Doesn't lock any object.
- */
-void VirtualBox::onMachineUninit(Machine *aMachine)
+int VirtualBox::natNetworkRefInc(IN_BSTR aNetworkName)
{
- postEvent(new MachineUninitEvent(this, aMachine));
+ AutoWriteLock safeLock(*spMtxNatNetworkNameToRefCountLock COMMA_LOCKVAL_SRC_POS);
+ Bstr name(aNetworkName);
+
+ if (!sNatNetworkNameToRefCount[name])
+ {
+ ComPtr<INATNetwork> nat;
+ HRESULT rc = FindNATNetworkByName(aNetworkName, nat.asOutParam());
+ if (FAILED(rc)) return -1;
+
+ rc = nat->Start(Bstr("whatever").raw());
+ if (SUCCEEDED(rc))
+ LogRel(("Started NAT network '%ls'\n", aNetworkName));
+ else
+ LogRel(("Error %Rhrc starting NAT network '%ls'\n", rc, aNetworkName));
+ AssertComRCReturn(rc, -1);
+ }
+
+ sNatNetworkNameToRefCount[name]++;
+
+ return sNatNetworkNameToRefCount[name];
}
-/**
- * @note Doesn't lock any object.
- */
-void VirtualBox::onNatRedirectChange(const Guid &aMachineId, ULONG ulSlot, bool fRemove, IN_BSTR aName,
- NATProtocol_T aProto, IN_BSTR aHostIp, uint16_t aHostPort,
- IN_BSTR aGuestIp, uint16_t aGuestPort)
+
+int VirtualBox::natNetworkRefDec(IN_BSTR aNetworkName)
{
- fireNATRedirectEvent(m->pEventSource, aMachineId.toUtf16().raw(), ulSlot, fRemove, aName, aProto, aHostIp,
- aHostPort, aGuestIp, aGuestPort);
+ AutoWriteLock safeLock(*spMtxNatNetworkNameToRefCountLock COMMA_LOCKVAL_SRC_POS);
+ Bstr name(aNetworkName);
+
+ if (!sNatNetworkNameToRefCount[name])
+ return 0;
+
+ sNatNetworkNameToRefCount[name]--;
+
+ if (!sNatNetworkNameToRefCount[name])
+ {
+ ComPtr<INATNetwork> nat;
+ HRESULT rc = FindNATNetworkByName(aNetworkName, nat.asOutParam());
+ if (FAILED(rc)) return -1;
+
+ rc = nat->Stop();
+ if (SUCCEEDED(rc))
+ LogRel(("Stopped NAT network '%ls'\n", aNetworkName));
+ else
+ LogRel(("Error %Rhrc stopping NAT network '%ls'\n", rc, aNetworkName));
+ AssertComRCReturn(rc, -1);
+ }
+
+ return sNatNetworkNameToRefCount[name];
}
+
/**
* @note Locks this object for reading.
*/
@@ -3161,6 +3217,19 @@ void VirtualBox::getOpenedMachines(SessionMachinesList &aMachines,
}
/**
+ * Gets a reference to the machine list. This is the real thing, not a copy,
+ * so bad things will happen if the caller doesn't hold the necessary lock.
+ *
+ * @returns reference to machine list
+ *
+ * @note Caller must hold the VirtualBox object lock at least for reading.
+ */
+VirtualBox::MachinesOList &VirtualBox::getMachinesList(void)
+{
+ return m->allMachines;
+}
+
+/**
* Searches for a machine object with the given ID in the collection
* of registered machines.
*
@@ -3402,7 +3471,7 @@ HRESULT VirtualBox::findHardDiskById(const Guid &id,
bool aSetError,
ComObjPtr<Medium> *aHardDisk /*= NULL*/)
{
- AssertReturn(!id.isEmpty(), E_INVALIDARG);
+ AssertReturn(!id.isZero(), E_INVALIDARG);
// we use the hard disks map, but it is protected by the
// hard disk _list_ lock handle
@@ -3609,12 +3678,19 @@ HRESULT VirtualBox::findRemoveableMedium(DeviceType_T mediumType,
bool aSetError,
ComObjPtr<Medium> &pMedium)
{
- if (uuid.isEmpty())
+ if (uuid.isZero())
{
// that's easy
pMedium.setNull();
return S_OK;
}
+ else if (!uuid.isValid())
+ {
+ /* handling of case invalid GUID */
+ return setError(VBOX_E_OBJECT_NOT_FOUND,
+ tr("Guid '%ls' is invalid"),
+ uuid.toString().c_str());
+ }
// first search for host drive with that UUID
HRESULT rc = m->pHost->findHostDriveById(mediumType,
@@ -3816,7 +3892,7 @@ HRESULT VirtualBox::checkMediaForConflicts(const Guid &aId,
Utf8Str &aConflict,
ComObjPtr<Medium> *ppMedium)
{
- AssertReturn(!aId.isEmpty() && !aLocation.isEmpty(), E_FAIL);
+ AssertReturn(!aId.isZero() && !aLocation.isEmpty(), E_FAIL);
AssertReturn(ppMedium, E_INVALIDARG);
aConflict.setNull();
@@ -3829,7 +3905,7 @@ HRESULT VirtualBox::checkMediaForConflicts(const Guid &aId,
ComObjPtr<Medium> pMediumFound;
const char *pcszType = NULL;
- if (!aId.isEmpty())
+ if (aId.isValid() && !aId.isZero())
rc = findHardDiskById(aId, false /* aSetError */, &pMediumFound);
if (FAILED(rc) && !aLocation.isEmpty())
rc = findHardDiskByLocation(aLocation, false /* aSetError */, &pMediumFound);
@@ -3873,6 +3949,49 @@ HRESULT VirtualBox::checkMediaForConflicts(const Guid &aId,
}
/**
+ * Checks whether the given UUID is already in use by one medium for the
+ * given device type.
+ *
+ * @returns true if the UUID is already in use
+ * fale otherwise
+ * @param aId The UUID to check.
+ * @param deviceType The device type the UUID is going to be checked for
+ * conflicts.
+ */
+bool VirtualBox::isMediaUuidInUse(const Guid &aId, DeviceType_T deviceType)
+{
+ /* A zero UUID is invalid here, always claim that it is already used. */
+ AssertReturn(!aId.isZero(), true);
+
+ AutoReadLock alock(getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
+
+ HRESULT rc = S_OK;
+ bool fInUse = false;
+
+ ComObjPtr<Medium> pMediumFound;
+
+ switch (deviceType)
+ {
+ case DeviceType_HardDisk:
+ rc = findHardDiskById(aId, false /* aSetError */, &pMediumFound);
+ break;
+ case DeviceType_DVD:
+ rc = findDVDOrFloppyImage(DeviceType_DVD, &aId, Utf8Str::Empty, false /* aSetError */, &pMediumFound);
+ break;
+ case DeviceType_Floppy:
+ rc = findDVDOrFloppyImage(DeviceType_Floppy, &aId, Utf8Str::Empty, false /* aSetError */, &pMediumFound);
+ break;
+ default:
+ AssertMsgFailed(("Invalid device type %d\n", deviceType));
+ }
+
+ if (SUCCEEDED(rc) && pMediumFound)
+ fInUse = true;
+
+ return fInUse;
+}
+
+/**
* Called from Machine::prepareSaveSettings() when it has detected
* that a machine has been renamed. Such renames will require
* updating the global media registry during the
@@ -4129,6 +4248,23 @@ HRESULT VirtualBox::saveSettings()
}
}
+#ifdef VBOX_WITH_NAT_SERVICE
+ /* Saving NAT Network configuration */
+ m->pMainConfigFile->llNATNetworks.clear();
+ {
+ AutoReadLock natNetworkLock(m->allNATNetworks.getLockHandle() COMMA_LOCKVAL_SRC_POS);
+ for (NATNetworksOList::const_iterator it = m->allNATNetworks.begin();
+ it != m->allNATNetworks.end();
+ ++it)
+ {
+ settings::NATNetwork n;
+ rc = (*it)->saveSettings(n);
+ if (FAILED(rc)) throw rc;
+ m->pMainConfigFile->llNATNetworks.push_back(n);
+ }
+ }
+#endif
+
// leave extra data alone, it's still in the config file
// host data (USB filters)
@@ -4418,7 +4554,7 @@ void VirtualBox::pushMediumToListWithChildren(MediaList &llMedia, Medium *pMediu
*/
HRESULT VirtualBox::unregisterMachineMedia(const Guid &uuidMachine)
{
- Assert(!uuidMachine.isEmpty());
+ Assert(!uuidMachine.isZero() && uuidMachine.isValid());
LogFlowFuncEnter();
@@ -4670,6 +4806,18 @@ const Utf8Str& VirtualBox::settingsFilePath()
}
/**
+ * Returns the lock handle which protects the machines list. As opposed
+ * to version 3.1 and earlier, these lists are no longer protected by the
+ * VirtualBox lock, but by this more specialized lock. Mind the locking
+ * order: always request this lock after the VirtualBox object lock but
+ * before the locks of any machine object. See AutoLock.h.
+ */
+RWLockHandle& VirtualBox::getMachinesListLockHandle()
+{
+ return m->lockMachines;
+}
+
+/**
* Returns the lock handle which protects the media trees (hard disks,
* DVDs, floppies). As opposed to version 3.1 and earlier, these lists
* are no longer protected by the VirtualBox lock, but by this more
@@ -4683,541 +4831,62 @@ RWLockHandle& VirtualBox::getMediaTreeLockHandle()
}
/**
- * Thread function that watches the termination of all client processes
- * that have opened sessions using IMachine::LockMachine()
+ * Thread function that handles custom events posted using #postEvent().
*/
// static
-DECLCALLBACK(int) VirtualBox::ClientWatcher(RTTHREAD /* thread */, void *pvUser)
+DECLCALLBACK(int) VirtualBox::AsyncEventHandler(RTTHREAD thread, void *pvUser)
{
LogFlowFuncEnter();
- VirtualBox *that = (VirtualBox*)pvUser;
- Assert(that);
-
- typedef std::vector< ComObjPtr<Machine> > MachineVector;
- typedef std::vector< ComObjPtr<SessionMachine> > SessionMachineVector;
-
- SessionMachineVector machines;
- MachineVector spawnedMachines;
-
- size_t cnt = 0;
- size_t cntSpawned = 0;
-
- VirtualBoxBase::initializeComForThread();
-
-#if defined(RT_OS_WINDOWS)
+ AssertReturn(pvUser, VERR_INVALID_POINTER);
- /// @todo (dmik) processes reaping!
+ HRESULT hr = com::Initialize();
+ if (FAILED(hr))
+ return VERR_COM_UNEXPECTED;
- HANDLE handles[MAXIMUM_WAIT_OBJECTS];
- handles[0] = that->m->updateReq;
+ int rc = VINF_SUCCESS;
- do
+ try
{
- AutoCaller autoCaller(that);
- /* VirtualBox has been early uninitialized, terminate */
- if (!autoCaller.isOk())
- break;
-
- do
- {
- /* release the caller to let uninit() ever proceed */
- autoCaller.release();
-
- DWORD rc = ::WaitForMultipleObjects((DWORD)(1 + cnt + cntSpawned),
- handles,
- FALSE,
- INFINITE);
-
- /* Restore the caller before using VirtualBox. If it fails, this
- * means VirtualBox is being uninitialized and we must terminate. */
- autoCaller.add();
- if (!autoCaller.isOk())
- break;
-
- bool update = false;
-
- if (rc == WAIT_OBJECT_0)
- {
- /* update event is signaled */
- update = true;
- }
- else if (rc > WAIT_OBJECT_0 && rc <= (WAIT_OBJECT_0 + cnt))
- {
- /* machine mutex is released */
- (machines[rc - WAIT_OBJECT_0 - 1])->checkForDeath();
- update = true;
- }
- else if (rc > WAIT_ABANDONED_0 && rc <= (WAIT_ABANDONED_0 + cnt))
- {
- /* machine mutex is abandoned due to client process termination */
- (machines[rc - WAIT_ABANDONED_0 - 1])->checkForDeath();
- update = true;
- }
- else if (rc > WAIT_OBJECT_0 + cnt && rc <= (WAIT_OBJECT_0 + cntSpawned))
- {
- /* spawned VM process has terminated (normally or abnormally) */
- (spawnedMachines[rc - WAIT_OBJECT_0 - cnt - 1])->
- checkForSpawnFailure();
- update = true;
- }
-
- if (update)
- {
- /* close old process handles */
- for (size_t i = 1 + cnt; i < 1 + cnt + cntSpawned; ++i)
- CloseHandle(handles[i]);
-
- // lock the machines list for reading
- AutoReadLock thatLock(that->m->allMachines.getLockHandle() COMMA_LOCKVAL_SRC_POS);
-
- /* obtain a new set of opened machines */
- cnt = 0;
- machines.clear();
-
- for (MachinesOList::iterator it = that->m->allMachines.begin();
- it != that->m->allMachines.end();
- ++it)
- {
- /// @todo handle situations with more than 64 objects
- AssertMsgBreak((1 + cnt) <= MAXIMUM_WAIT_OBJECTS,
- ("MAXIMUM_WAIT_OBJECTS reached"));
-
- ComObjPtr<SessionMachine> sm;
- HANDLE ipcSem;
- if ((*it)->isSessionOpenOrClosing(sm, NULL, &ipcSem))
- {
- machines.push_back(sm);
- handles[1 + cnt] = ipcSem;
- ++cnt;
- }
- }
-
- LogFlowFunc(("UPDATE: direct session count = %d\n", cnt));
-
- /* obtain a new set of spawned machines */
- cntSpawned = 0;
- spawnedMachines.clear();
+ /* Create an event queue for the current thread. */
+ EventQueue *pEventQueue = new EventQueue();
+ AssertPtr(pEventQueue);
- for (MachinesOList::iterator it = that->m->allMachines.begin();
- it != that->m->allMachines.end();
- ++it)
- {
- /// @todo handle situations with more than 64 objects
- AssertMsgBreak((1 + cnt + cntSpawned) <= MAXIMUM_WAIT_OBJECTS,
- ("MAXIMUM_WAIT_OBJECTS reached"));
-
- RTPROCESS pid;
- if ((*it)->isSessionSpawning(&pid))
- {
- HANDLE ph = OpenProcess(SYNCHRONIZE, FALSE, pid);
- AssertMsg(ph != NULL, ("OpenProcess (pid=%d) failed with %d\n",
- pid, GetLastError()));
- if (rc == 0)
- {
- spawnedMachines.push_back(*it);
- handles[1 + cnt + cntSpawned] = ph;
- ++cntSpawned;
- }
- }
- }
-
- LogFlowFunc(("UPDATE: spawned session count = %d\n", cntSpawned));
-
- // machines lock unwinds here
- }
- }
- while (true);
- }
- while (0);
-
- /* close old process handles */
- for (size_t i = 1 + cnt; i < 1 + cnt + cntSpawned; ++ i)
- CloseHandle(handles[i]);
-
- /* release sets of machines if any */
- machines.clear();
- spawnedMachines.clear();
-
- ::CoUninitialize();
-
-#elif defined(RT_OS_OS2)
-
- /// @todo (dmik) processes reaping!
+ /* Return the queue to the one who created this thread. */
+ *(static_cast <EventQueue **>(pvUser)) = pEventQueue;
- /* according to PMREF, 64 is the maximum for the muxwait list */
- SEMRECORD handles[64];
+ /* signal that we're ready. */
+ RTThreadUserSignal(thread);
- HMUX muxSem = NULLHANDLE;
-
- do
- {
- AutoCaller autoCaller(that);
- /* VirtualBox has been early uninitialized, terminate */
- if (!autoCaller.isOk())
- break;
-
- do
+ /*
+ * In case of spurious wakeups causing VERR_TIMEOUTs and/or other return codes
+ * we must not stop processing events and delete the pEventQueue object. This must
+ * be done ONLY when we stop this loop via interruptEventQueueProcessing().
+ * See @bugref{5724}.
+ */
+ for (;;)
{
- /* release the caller to let uninit() ever proceed */
- autoCaller.release();
-
- int vrc = RTSemEventWait(that->m->updateReq, 500);
-
- /* Restore the caller before using VirtualBox. If it fails, this
- * means VirtualBox is being uninitialized and we must terminate. */
- autoCaller.add();
- if (!autoCaller.isOk())
- break;
-
- bool update = false;
- bool updateSpawned = false;
-
- if (RT_SUCCESS(vrc))
- {
- /* update event is signaled */
- update = true;
- updateSpawned = true;
- }
- else
- {
- AssertMsg(vrc == VERR_TIMEOUT || vrc == VERR_INTERRUPTED,
- ("RTSemEventWait returned %Rrc\n", vrc));
-
- /* are there any mutexes? */
- if (cnt > 0)
- {
- /* figure out what's going on with machines */
-
- unsigned long semId = 0;
- APIRET arc = ::DosWaitMuxWaitSem(muxSem,
- SEM_IMMEDIATE_RETURN, &semId);
-
- if (arc == NO_ERROR)
- {
- /* machine mutex is normally released */
- Assert(semId >= 0 && semId < cnt);
- if (semId >= 0 && semId < cnt)
- {
-#if 0//def DEBUG
- {
- AutoReadLock machineLock(machines[semId] COMMA_LOCKVAL_SRC_POS);
- LogFlowFunc(("released mutex: machine='%ls'\n",
- machines[semId]->name().raw()));
- }
-#endif
- machines[semId]->checkForDeath();
- }
- update = true;
- }
- else if (arc == ERROR_SEM_OWNER_DIED)
- {
- /* machine mutex is abandoned due to client process
- * termination; find which mutex is in the Owner Died
- * state */
- for (size_t i = 0; i < cnt; ++ i)
- {
- PID pid; TID tid;
- unsigned long reqCnt;
- arc = DosQueryMutexSem((HMTX)handles[i].hsemCur, &pid, &tid, &reqCnt);
- if (arc == ERROR_SEM_OWNER_DIED)
- {
- /* close the dead mutex as asked by PMREF */
- ::DosCloseMutexSem((HMTX)handles[i].hsemCur);
-
- Assert(i >= 0 && i < cnt);
- if (i >= 0 && i < cnt)
- {
-#if 0//def DEBUG
- {
- AutoReadLock machineLock(machines[semId] COMMA_LOCKVAL_SRC_POS);
- LogFlowFunc(("mutex owner dead: machine='%ls'\n",
- machines[i]->name().raw()));
- }
-#endif
- machines[i]->checkForDeath();
- }
- }
- }
- update = true;
- }
- else
- AssertMsg(arc == ERROR_INTERRUPT || arc == ERROR_TIMEOUT,
- ("DosWaitMuxWaitSem returned %d\n", arc));
- }
-
- /* are there any spawning sessions? */
- if (cntSpawned > 0)
- {
- for (size_t i = 0; i < cntSpawned; ++ i)
- updateSpawned |= (spawnedMachines[i])->
- checkForSpawnFailure();
- }
- }
-
- if (update || updateSpawned)
+ rc = pEventQueue->processEventQueue(RT_INDEFINITE_WAIT);
+ if (rc == VERR_INTERRUPTED)
{
- AutoReadLock thatLock(that COMMA_LOCKVAL_SRC_POS);
-
- if (update)
- {
- /* close the old muxsem */
- if (muxSem != NULLHANDLE)
- ::DosCloseMuxWaitSem(muxSem);
-
- /* obtain a new set of opened machines */
- cnt = 0;
- machines.clear();
-
- for (MachinesOList::iterator it = that->m->allMachines.begin();
- it != that->m->allMachines.end(); ++ it)
- {
- /// @todo handle situations with more than 64 objects
- AssertMsg(cnt <= 64 /* according to PMREF */,
- ("maximum of 64 mutex semaphores reached (%d)",
- cnt));
-
- ComObjPtr<SessionMachine> sm;
- HMTX ipcSem;
- if ((*it)->isSessionOpenOrClosing(sm, NULL, &ipcSem))
- {
- machines.push_back(sm);
- handles[cnt].hsemCur = (HSEM)ipcSem;
- handles[cnt].ulUser = cnt;
- ++ cnt;
- }
- }
-
- LogFlowFunc(("UPDATE: direct session count = %d\n", cnt));
-
- if (cnt > 0)
- {
- /* create a new muxsem */
- APIRET arc = ::DosCreateMuxWaitSem(NULL, &muxSem, cnt,
- handles,
- DCMW_WAIT_ANY);
- AssertMsg(arc == NO_ERROR,
- ("DosCreateMuxWaitSem returned %d\n", arc));
- NOREF(arc);
- }
- }
-
- if (updateSpawned)
- {
- /* obtain a new set of spawned machines */
- spawnedMachines.clear();
-
- for (MachinesOList::iterator it = that->m->allMachines.begin();
- it != that->m->allMachines.end(); ++ it)
- {
- if ((*it)->isSessionSpawning())
- spawnedMachines.push_back(*it);
- }
-
- cntSpawned = spawnedMachines.size();
- LogFlowFunc(("UPDATE: spawned session count = %d\n", cntSpawned));
- }
+ LogFlow(("Event queue processing ended with rc=%Rrc\n", rc));
+ rc = VINF_SUCCESS; /* Set success when exiting. */
+ break;
}
}
- while (true);
- }
- while (0);
-
- /* close the muxsem */
- if (muxSem != NULLHANDLE)
- ::DosCloseMuxWaitSem(muxSem);
-
- /* release sets of machines if any */
- machines.clear();
- spawnedMachines.clear();
-
-#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
- bool update = false;
- bool updateSpawned = false;
-
- do
+ delete pEventQueue;
+ }
+ catch (std::bad_alloc &ba)
{
- AutoCaller autoCaller(that);
- if (!autoCaller.isOk())
- break;
-
- do
- {
- /* release the caller to let uninit() ever proceed */
- autoCaller.release();
-
- /* determine wait timeout adaptively: after updating information
- * relevant to the client watcher, check a few times more
- * frequently. This ensures good reaction time when the signalling
- * has to be done a bit before the actual change for technical
- * reasons, and saves CPU cycles when no activities are expected. */
- RTMSINTERVAL cMillies;
- {
- uint8_t uOld, uNew;
- do
- {
- uOld = ASMAtomicUoReadU8(&that->m->updateAdaptCtr);
- uNew = uOld ? uOld - 1 : uOld;
- } while (!ASMAtomicCmpXchgU8(&that->m->updateAdaptCtr, uNew, uOld));
- Assert(uOld <= RT_ELEMENTS(s_updateAdaptTimeouts) - 1);
- cMillies = s_updateAdaptTimeouts[uOld];
- }
-
- int rc = RTSemEventWait(that->m->updateReq, cMillies);
-
- /*
- * Restore the caller before using VirtualBox. If it fails, this
- * means VirtualBox is being uninitialized and we must terminate.
- */
- autoCaller.add();
- if (!autoCaller.isOk())
- break;
-
- if (RT_SUCCESS(rc) || update || updateSpawned)
- {
- /* RT_SUCCESS(rc) means an update event is signaled */
-
- // lock the machines list for reading
- AutoReadLock thatLock(that->m->allMachines.getLockHandle() COMMA_LOCKVAL_SRC_POS);
-
- if (RT_SUCCESS(rc) || update)
- {
- /* obtain a new set of opened machines */
- machines.clear();
-
- for (MachinesOList::iterator it = that->m->allMachines.begin();
- it != that->m->allMachines.end();
- ++it)
- {
- ComObjPtr<SessionMachine> sm;
- if ((*it)->isSessionOpenOrClosing(sm))
- machines.push_back(sm);
- }
-
- cnt = machines.size();
- LogFlowFunc(("UPDATE: direct session count = %d\n", cnt));
- }
-
- if (RT_SUCCESS(rc) || updateSpawned)
- {
- /* obtain a new set of spawned machines */
- spawnedMachines.clear();
-
- for (MachinesOList::iterator it = that->m->allMachines.begin();
- it != that->m->allMachines.end();
- ++it)
- {
- if ((*it)->isSessionSpawning())
- spawnedMachines.push_back(*it);
- }
-
- cntSpawned = spawnedMachines.size();
- LogFlowFunc(("UPDATE: spawned session count = %d\n", cntSpawned));
- }
-
- // machines lock unwinds here
- }
-
- update = false;
- for (size_t i = 0; i < cnt; ++ i)
- update |= (machines[i])->checkForDeath();
-
- updateSpawned = false;
- for (size_t i = 0; i < cntSpawned; ++ i)
- updateSpawned |= (spawnedMachines[i])->checkForSpawnFailure();
-
- /* reap child processes */
- {
- AutoWriteLock alock(that COMMA_LOCKVAL_SRC_POS);
- if (that->m->llProcesses.size())
- {
- LogFlowFunc(("UPDATE: child process count = %d\n",
- that->m->llProcesses.size()));
- VirtualBox::Data::ProcessList::iterator it = that->m->llProcesses.begin();
- while (it != that->m->llProcesses.end())
- {
- RTPROCESS pid = *it;
- RTPROCSTATUS status;
- int vrc = ::RTProcWait(pid, RTPROCWAIT_FLAGS_NOBLOCK, &status);
- if (vrc == VINF_SUCCESS)
- {
- LogFlowFunc(("pid %d (%x) was reaped, status=%d, reason=%d\n",
- pid, pid, status.iStatus,
- status.enmReason));
- it = that->m->llProcesses.erase(it);
- }
- else
- {
- LogFlowFunc(("pid %d (%x) was NOT reaped, vrc=%Rrc\n",
- pid, pid, vrc));
- if (vrc != VERR_PROCESS_RUNNING)
- {
- /* remove the process if it is not already running */
- it = that->m->llProcesses.erase(it);
- }
- else
- ++ it;
- }
- }
- }
- }
- }
- while (true);
+ rc = VERR_NO_MEMORY;
+ NOREF(ba);
}
- while (0);
-
- /* release sets of machines if any */
- machines.clear();
- spawnedMachines.clear();
-
-#else
-# error "Port me!"
-#endif
-
- VirtualBoxBase::uninitializeComForThread();
- LogFlowFuncLeave();
- return 0;
-}
-
-/**
- * Thread function that handles custom events posted using #postEvent().
- */
-// static
-DECLCALLBACK(int) VirtualBox::AsyncEventHandler(RTTHREAD thread, void *pvUser)
-{
- LogFlowFuncEnter();
-
- AssertReturn(pvUser, VERR_INVALID_POINTER);
-
- com::Initialize();
-
- // create an event queue for the current thread
- EventQueue *eventQ = new EventQueue();
- AssertReturn(eventQ, VERR_NO_MEMORY);
-
- // return the queue to the one who created this thread
- *(static_cast <EventQueue **>(pvUser)) = eventQ;
- // signal that we're ready
- RTThreadUserSignal(thread);
-
- /*
- * In case of spurious wakeups causing VERR_TIMEOUTs and/or other return codes
- * we must not stop processing events and delete the "eventQ" object. This must
- * be done ONLY when we stop this loop via interruptEventQueueProcessing().
- * See @bugref{5724}.
- */
- while (eventQ->processEventQueue(RT_INDEFINITE_WAIT) != VERR_INTERRUPTED)
- /* nothing */ ;
-
- delete eventQ;
com::Shutdown();
-
- LogFlowFuncLeave();
-
- return 0;
+ LogFlowFuncLeaveRC(rc);
+ return rc;
}
@@ -5422,4 +5091,204 @@ HRESULT VirtualBox::unregisterDHCPServer(DHCPServer *aDHCPServer,
return rc;
}
+
+/**
+ * NAT Network
+ */
+
+STDMETHODIMP VirtualBox::CreateNATNetwork(IN_BSTR aName, INATNetwork ** aNatNetwork)
+{
+#ifdef VBOX_WITH_NAT_SERVICE
+ CheckComArgStrNotEmptyOrNull(aName);
+ CheckComArgNotNull(aNatNetwork);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ ComObjPtr<NATNetwork> natNetwork;
+ natNetwork.createObject();
+ HRESULT rc = natNetwork->init(this, aName);
+ if (FAILED(rc)) return rc;
+
+ rc = registerNATNetwork(natNetwork, true);
+ if (FAILED(rc)) return rc;
+
+ natNetwork.queryInterfaceTo(aNatNetwork);
+
+ fireNATNetworkCreationDeletionEvent(m->pEventSource, aName, TRUE);
+ return rc;
+#else
+ NOREF(aName);
+ NOREF(aNatNetwork);
+ return E_NOTIMPL;
+#endif
+}
+
+STDMETHODIMP VirtualBox::FindNATNetworkByName(IN_BSTR aName, INATNetwork ** aNetwork)
+{
+#ifdef VBOX_WITH_NAT_SERVICE
+ CheckComArgStrNotEmptyOrNull(aName);
+ CheckComArgNotNull(aNetwork);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ HRESULT rc;
+ Bstr bstr;
+ ComPtr<NATNetwork> found;
+
+ AutoReadLock alock(m->allNATNetworks.getLockHandle() COMMA_LOCKVAL_SRC_POS);
+
+ for (NATNetworksOList::const_iterator it = m->allNATNetworks.begin();
+ it != m->allNATNetworks.end();
+ ++it)
+ {
+ rc = (*it)->COMGETTER(NetworkName)(bstr.asOutParam());
+ if (FAILED(rc)) return rc;
+
+ if (bstr == aName)
+ {
+ found = *it;
+ break;
+ }
+ }
+
+ if (!found)
+ return E_INVALIDARG;
+
+ return found.queryInterfaceTo(aNetwork);
+#else
+ NOREF(aName);
+ NOREF(aNetwork);
+ return E_NOTIMPL;
+#endif
+}
+
+STDMETHODIMP VirtualBox::RemoveNATNetwork(INATNetwork * aNetwork)
+{
+#ifdef VBOX_WITH_NAT_SERVICE
+ CheckComArgNotNull(aNetwork);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+ Bstr name;
+ HRESULT rc;
+ NATNetwork *network = static_cast<NATNetwork *>(aNetwork);
+ rc = network->COMGETTER(NetworkName)(name.asOutParam());
+ rc = unregisterNATNetwork(network, true);
+ fireNATNetworkCreationDeletionEvent(m->pEventSource, name.raw(), FALSE);
+ return rc;
+#else
+ NOREF(aNetwork);
+ return E_NOTIMPL;
+#endif
+
+}
+/**
+ * Remembers the given NAT network in the settings.
+ *
+ * @param aNATNetwork NAT Network object to remember.
+ * @param aSaveSettings @c true to save settings to disk (default).
+ *
+ *
+ * @note Locks this object for writing and @a aNATNetwork for reading.
+ */
+HRESULT VirtualBox::registerNATNetwork(NATNetwork *aNATNetwork,
+ bool aSaveSettings /*= true*/)
+{
+#ifdef VBOX_WITH_NAT_SERVICE
+ AssertReturn(aNATNetwork != NULL, E_INVALIDARG);
+
+ AutoCaller autoCaller(this);
+ AssertComRCReturnRC(autoCaller.rc());
+
+ AutoCaller natNetworkCaller(aNATNetwork);
+ AssertComRCReturnRC(natNetworkCaller.rc());
+
+ Bstr name;
+ HRESULT rc;
+ rc = aNATNetwork->COMGETTER(NetworkName)(name.asOutParam());
+ AssertComRCReturnRC(rc);
+
+ /* returned value isn't 0 and aSaveSettings is true
+ * means that we create duplicate, otherwise we just load settings.
+ */
+ if ( sNatNetworkNameToRefCount[name]
+ && aSaveSettings)
+ AssertComRCReturnRC(E_INVALIDARG);
+
+ rc = S_OK;
+
+ sNatNetworkNameToRefCount[name] = 0;
+
+ m->allNATNetworks.addChild(aNATNetwork);
+
+ if (aSaveSettings)
+ {
+ AutoWriteLock vboxLock(this COMMA_LOCKVAL_SRC_POS);
+ rc = saveSettings();
+ vboxLock.release();
+
+ if (FAILED(rc))
+ unregisterNATNetwork(aNATNetwork, false /* aSaveSettings */);
+ }
+
+ return rc;
+#else
+ NOREF(aNATNetwork);
+ NOREF(aSaveSettings);
+ /* No panic please (silently ignore) */
+ return S_OK;
+#endif
+}
+
+/**
+ * Removes the given NAT network from the settings.
+ *
+ * @param aNATNetwork NAT network object to remove.
+ * @param aSaveSettings @c true to save settings to disk (default).
+ *
+ * When @a aSaveSettings is @c true, this operation may fail because of the
+ * failed #saveSettings() method it calls. In this case, the DHCP server
+ * will NOT be removed from the settingsi when this method returns.
+ *
+ * @note Locks this object for writing.
+ */
+HRESULT VirtualBox::unregisterNATNetwork(NATNetwork *aNATNetwork,
+ bool aSaveSettings /*= true*/)
+{
+#ifdef VBOX_WITH_NAT_SERVICE
+ AssertReturn(aNATNetwork != NULL, E_INVALIDARG);
+
+ AutoCaller autoCaller(this);
+ AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
+
+ AutoCaller natNetworkCaller(aNATNetwork);
+ AssertComRCReturn(natNetworkCaller.rc(), natNetworkCaller.rc());
+
+ Bstr name;
+ HRESULT rc = aNATNetwork->COMGETTER(NetworkName)(name.asOutParam());
+ /* Hm, there're still running clients. */
+ if (FAILED(rc) || sNatNetworkNameToRefCount[name])
+ AssertComRCReturnRC(E_INVALIDARG);
+
+ m->allNATNetworks.removeChild(aNATNetwork);
+
+ if (aSaveSettings)
+ {
+ AutoWriteLock vboxLock(this COMMA_LOCKVAL_SRC_POS);
+ rc = saveSettings();
+ vboxLock.release();
+
+ if (FAILED(rc))
+ registerNATNetwork(aNATNetwork, false /* aSaveSettings */);
+ }
+
+ return rc;
+#else
+ NOREF(aNATNetwork);
+ NOREF(aSaveSettings);
+ return E_NOTIMPL;
+#endif
+}
/* vi: set tabstop=4 shiftwidth=4 expandtab: */
diff --git a/src/VBox/Main/src-server/darwin/HostDnsServiceDarwin.cpp b/src/VBox/Main/src-server/darwin/HostDnsServiceDarwin.cpp
new file mode 100644
index 00000000..6e91e7e6
--- /dev/null
+++ b/src/VBox/Main/src-server/darwin/HostDnsServiceDarwin.cpp
@@ -0,0 +1,256 @@
+/* $Id: HostDnsServiceDarwin.cpp $ */
+/** @file
+ * Darwin specific DNS information fetching.
+ */
+
+/*
+ * Copyright (C) 2004-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include <VBox/com/string.h>
+#include <VBox/com/ptr.h>
+
+
+#include <iprt/err.h>
+#include <iprt/thread.h>
+#include <iprt/semaphore.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <SystemConfiguration/SCDynamicStore.h>
+
+#include <string>
+#include <vector>
+#include "../HostDnsService.h"
+
+
+struct HostDnsServiceDarwin::Data
+{
+ SCDynamicStoreRef m_store;
+ CFRunLoopSourceRef m_DnsWatcher;
+ CFRunLoopRef m_RunLoopRef;
+ CFRunLoopSourceRef m_Stopper;
+ bool m_fStop;
+ RTSEMEVENT m_evtStop;
+ static void performShutdownCallback(void *);
+};
+
+
+static const CFStringRef kStateNetworkGlobalDNSKey = CFSTR("State:/Network/Global/DNS");
+
+
+HostDnsServiceDarwin::HostDnsServiceDarwin():HostDnsMonitor(true),m(NULL)
+{
+ m = new HostDnsServiceDarwin::Data();
+}
+
+
+HostDnsServiceDarwin::~HostDnsServiceDarwin()
+{
+ if (!m)
+ return;
+
+ monitorThreadShutdown();
+
+ CFRelease(m->m_RunLoopRef);
+
+ CFRelease(m->m_DnsWatcher);
+
+ CFRelease(m->m_store);
+
+ RTSemEventDestroy(m->m_evtStop);
+
+ delete m;
+ m = NULL;
+}
+
+
+void HostDnsServiceDarwin::hostDnsServiceStoreCallback(void *, void *, void *info)
+{
+ HostDnsServiceDarwin *pThis = (HostDnsServiceDarwin *)info;
+
+ ALock l(pThis);
+ pThis->updateInfo();
+ pThis->notifyAll();
+}
+
+
+HRESULT HostDnsServiceDarwin::init()
+{
+ SCDynamicStoreContext ctx;
+ RT_ZERO(ctx);
+
+ ctx.info = this;
+
+ m->m_store = SCDynamicStoreCreate(NULL, CFSTR("org.virtualbox.VBoxSVC"),
+ (SCDynamicStoreCallBack)HostDnsServiceDarwin::hostDnsServiceStoreCallback,
+ &ctx);
+ AssertReturn(m->m_store, E_FAIL);
+
+ m->m_DnsWatcher = SCDynamicStoreCreateRunLoopSource(NULL, m->m_store, 0);
+ if (!m->m_DnsWatcher)
+ return E_OUTOFMEMORY;
+
+ int rc = RTSemEventCreate(&m->m_evtStop);
+ AssertRCReturn(rc, E_FAIL);
+
+ CFRunLoopSourceContext sctx;
+ RT_ZERO(sctx);
+ sctx.perform = HostDnsServiceDarwin::Data::performShutdownCallback;
+ m->m_Stopper = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &sctx);
+ AssertReturn(m->m_Stopper, E_FAIL);
+
+ HRESULT hrc = HostDnsMonitor::init();
+ AssertComRCReturn(hrc, hrc);
+
+ return updateInfo();
+}
+
+
+void HostDnsServiceDarwin::monitorThreadShutdown()
+{
+ ALock l(this);
+ if (!m->m_fStop)
+ {
+ CFRunLoopSourceSignal(m->m_Stopper);
+ CFRunLoopWakeUp(m->m_RunLoopRef);
+
+ RTSemEventWait(m->m_evtStop, RT_INDEFINITE_WAIT);
+ }
+}
+
+
+int HostDnsServiceDarwin::monitorWorker()
+{
+ m->m_RunLoopRef = CFRunLoopGetCurrent();
+ AssertReturn(m->m_RunLoopRef, VERR_INTERNAL_ERROR);
+
+ CFRetain(m->m_RunLoopRef);
+
+ CFArrayRef watchingArrayRef = CFArrayCreate(NULL,
+ (const void **)&kStateNetworkGlobalDNSKey,
+ 1, &kCFTypeArrayCallBacks);
+ if (!watchingArrayRef)
+ {
+ CFRelease(m->m_DnsWatcher);
+ return E_OUTOFMEMORY;
+ }
+
+ if(SCDynamicStoreSetNotificationKeys(m->m_store, watchingArrayRef, NULL))
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), m->m_DnsWatcher, kCFRunLoopCommonModes);
+
+ CFRelease(watchingArrayRef);
+
+ monitorThreadInitializationDone();
+
+ while (!m->m_fStop)
+ {
+ CFRunLoopRun();
+ }
+
+ CFRelease(m->m_RunLoopRef);
+
+ /* We're notifying stopper thread. */
+ RTSemEventSignal(m->m_evtStop);
+
+ return VINF_SUCCESS;
+}
+
+
+HRESULT HostDnsServiceDarwin::updateInfo()
+{
+ CFPropertyListRef propertyRef = SCDynamicStoreCopyValue(m->m_store,
+ kStateNetworkGlobalDNSKey);
+ /**
+ * 0:vvl@nb-mbp-i7-2(0)# scutil
+ * > get State:/Network/Global/DNS
+ * > d.show
+ * <dictionary> {
+ * DomainName : vvl-domain
+ * SearchDomains : <array> {
+ * 0 : vvl-domain
+ * 1 : de.vvl-domain.com
+ * }
+ * ServerAddresses : <array> {
+ * 0 : 192.168.1.4
+ * 1 : 192.168.1.1
+ * 2 : 8.8.4.4
+ * }
+ * }
+ */
+
+ if (!propertyRef)
+ return S_OK;
+
+ HostDnsInformation info;
+ CFStringRef domainNameRef = (CFStringRef)CFDictionaryGetValue(
+ static_cast<CFDictionaryRef>(propertyRef), CFSTR("DomainName"));
+ if (domainNameRef)
+ {
+ const char *pszDomainName = CFStringGetCStringPtr(domainNameRef,
+ CFStringGetSystemEncoding());
+ if (pszDomainName)
+ info.domain = pszDomainName;
+ }
+
+ int i, arrayCount;
+ CFArrayRef serverArrayRef = (CFArrayRef)CFDictionaryGetValue(
+ static_cast<CFDictionaryRef>(propertyRef), CFSTR("ServerAddresses"));
+ if (serverArrayRef)
+ {
+ arrayCount = CFArrayGetCount(serverArrayRef);
+ for (i = 0; i < arrayCount; ++i)
+ {
+ CFStringRef serverAddressRef = (CFStringRef)CFArrayGetValueAtIndex(serverArrayRef, i);
+ if (!serverArrayRef)
+ continue;
+
+ const char *pszServerAddress = CFStringGetCStringPtr(serverAddressRef,
+ CFStringGetSystemEncoding());
+ if (!pszServerAddress)
+ continue;
+
+ info.servers.push_back(std::string(pszServerAddress));
+ }
+ }
+
+ CFArrayRef searchArrayRef = (CFArrayRef)CFDictionaryGetValue(
+ static_cast<CFDictionaryRef>(propertyRef), CFSTR("SearchDomains"));
+ if (searchArrayRef)
+ {
+ arrayCount = CFArrayGetCount(searchArrayRef);
+
+ for (i = 0; i < arrayCount; ++i)
+ {
+ CFStringRef searchStringRef = (CFStringRef)CFArrayGetValueAtIndex(searchArrayRef, i);
+ if (!searchArrayRef)
+ continue;
+
+ const char *pszSearchString = CFStringGetCStringPtr(searchStringRef,
+ CFStringGetSystemEncoding());
+ if (!pszSearchString)
+ continue;
+
+ info.searchList.push_back(std::string(pszSearchString));
+ }
+ }
+
+ CFRelease(propertyRef);
+
+ setInfo(info);
+
+ return S_OK;
+}
+
+void HostDnsServiceDarwin::Data::performShutdownCallback(void *info)
+{
+ HostDnsServiceDarwin::Data *pThis = static_cast<HostDnsServiceDarwin::Data *>(info);
+ pThis->m_fStop = true;
+}
diff --git a/src/VBox/Main/src-server/darwin/HostPowerDarwin.cpp b/src/VBox/Main/src-server/darwin/HostPowerDarwin.cpp
index a83297e4..5e68d02b 100644
--- a/src/VBox/Main/src-server/darwin/HostPowerDarwin.cpp
+++ b/src/VBox/Main/src-server/darwin/HostPowerDarwin.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -25,43 +25,43 @@
#define POWER_SOURCE_OUTLET 1
#define POWER_SOURCE_BATTERY 2
-HostPowerServiceDarwin::HostPowerServiceDarwin (VirtualBox *aVirtualBox)
- : HostPowerService (aVirtualBox)
- , mThread (NULL)
- , mRootPort (MACH_PORT_NULL)
- , mNotifyPort (nil)
- , mRunLoop (nil)
- , mCritical (false)
+HostPowerServiceDarwin::HostPowerServiceDarwin(VirtualBox *aVirtualBox)
+ : HostPowerService(aVirtualBox)
+ , mThread(NULL)
+ , mRootPort(MACH_PORT_NULL)
+ , mNotifyPort(nil)
+ , mRunLoop(nil)
+ , mCritical(false)
{
/* Create the new worker thread. */
- int rc = RTThreadCreate (&mThread, HostPowerServiceDarwin::powerChangeNotificationThread, this, 65536,
- RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "MainPower");
+ int rc = RTThreadCreate(&mThread, HostPowerServiceDarwin::powerChangeNotificationThread, this, 65536,
+ RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "MainPower");
if (RT_FAILURE(rc))
- LogFlow (("RTThreadCreate failed with %Rrc\n", rc));
+ LogFlow(("RTThreadCreate failed with %Rrc\n", rc));
}
HostPowerServiceDarwin::~HostPowerServiceDarwin()
{
/* Jump out of the run loop. */
- CFRunLoopStop (mRunLoop);
+ CFRunLoopStop(mRunLoop);
/* Remove the sleep notification port from the application runloop. */
- CFRunLoopRemoveSource (CFRunLoopGetCurrent(),
- IONotificationPortGetRunLoopSource (mNotifyPort),
- kCFRunLoopCommonModes);
+ CFRunLoopRemoveSource(CFRunLoopGetCurrent(),
+ IONotificationPortGetRunLoopSource(mNotifyPort),
+ kCFRunLoopCommonModes);
/* Deregister for system sleep notifications. */
- IODeregisterForSystemPower (&mNotifierObject);
+ IODeregisterForSystemPower(&mNotifierObject);
/* IORegisterForSystemPower implicitly opens the Root Power Domain
* IOService so we close it here. */
- IOServiceClose (mRootPort);
+ IOServiceClose(mRootPort);
/* Destroy the notification port allocated by IORegisterForSystemPower */
- IONotificationPortDestroy (mNotifyPort);
+ IONotificationPortDestroy(mNotifyPort);
}
-DECLCALLBACK(int) HostPowerServiceDarwin::powerChangeNotificationThread (RTTHREAD /* ThreadSelf */, void *pInstance)
+DECLCALLBACK(int) HostPowerServiceDarwin::powerChangeNotificationThread(RTTHREAD /* ThreadSelf */, void *pInstance)
{
- HostPowerServiceDarwin *pPowerObj = static_cast<HostPowerServiceDarwin *> (pInstance);
+ HostPowerServiceDarwin *pPowerObj = static_cast<HostPowerServiceDarwin *>(pInstance);
/* We have to initial set the critical state of the battery, cause we want
* not the HostPowerService to inform about that state when a VM starts.
@@ -69,19 +69,19 @@ DECLCALLBACK(int) HostPowerServiceDarwin::powerChangeNotificationThread (RTTHREA
pPowerObj->checkBatteryCriticalLevel();
/* Register to receive system sleep notifications */
- pPowerObj->mRootPort = IORegisterForSystemPower (pPowerObj, &pPowerObj->mNotifyPort,
- HostPowerServiceDarwin::powerChangeNotificationHandler,
- &pPowerObj->mNotifierObject);
+ pPowerObj->mRootPort = IORegisterForSystemPower(pPowerObj, &pPowerObj->mNotifyPort,
+ HostPowerServiceDarwin::powerChangeNotificationHandler,
+ &pPowerObj->mNotifierObject);
if (pPowerObj->mRootPort == MACH_PORT_NULL)
{
- LogFlow (("IORegisterForSystemPower failed\n"));
+ LogFlow(("IORegisterForSystemPower failed\n"));
return VERR_NOT_SUPPORTED;
}
pPowerObj->mRunLoop = CFRunLoopGetCurrent();
/* Add the notification port to the application runloop */
- CFRunLoopAddSource (pPowerObj->mRunLoop,
- IONotificationPortGetRunLoopSource (pPowerObj->mNotifyPort),
- kCFRunLoopCommonModes);
+ CFRunLoopAddSource(pPowerObj->mRunLoop,
+ IONotificationPortGetRunLoopSource(pPowerObj->mNotifyPort),
+ kCFRunLoopCommonModes);
/* Register for all battery change events. The handler will check for low
* power events itself. */
@@ -96,10 +96,10 @@ DECLCALLBACK(int) HostPowerServiceDarwin::powerChangeNotificationThread (RTTHREA
return VINF_SUCCESS;
}
-void HostPowerServiceDarwin::powerChangeNotificationHandler (void *pvData, io_service_t /* service */, natural_t messageType, void *pMessageArgument)
+void HostPowerServiceDarwin::powerChangeNotificationHandler(void *pvData, io_service_t /* service */, natural_t messageType, void *pMessageArgument)
{
- HostPowerServiceDarwin *pPowerObj = static_cast<HostPowerServiceDarwin *> (pvData);
- Log (( "powerChangeNotificationHandler: messageType %08lx, arg %08lx\n", (long unsigned int)messageType, (long unsigned int)pMessageArgument));
+ HostPowerServiceDarwin *pPowerObj = static_cast<HostPowerServiceDarwin *>(pvData);
+ Log(( "powerChangeNotificationHandler: messageType %08lx, arg %08lx\n", (long unsigned int)messageType, (long unsigned int)pMessageArgument));
switch (messageType)
{
@@ -113,18 +113,18 @@ void HostPowerServiceDarwin::powerChangeNotificationHandler (void *pvData, io_se
* you don't acknowledge this power change by calling either
* IOAllowPowerChange or IOCancelPowerChange, the system will
* wait 30 seconds then go to sleep. */
- IOAllowPowerChange (pPowerObj->mRootPort, reinterpret_cast<long> (pMessageArgument));
+ IOAllowPowerChange(pPowerObj->mRootPort, reinterpret_cast<long>(pMessageArgument));
break;
}
case kIOMessageSystemWillSleep:
{
/* The system will go for sleep. */
- pPowerObj->notify (HostPowerEvent_Suspend);
+ pPowerObj->notify(Reason_HostSuspend);
/* If you do not call IOAllowPowerChange or IOCancelPowerChange to
* acknowledge this message, sleep will be delayed by 30 seconds.
* NOTE: If you call IOCancelPowerChange to deny sleep it returns
* kIOReturnSuccess, however the system WILL still go to sleep. */
- IOAllowPowerChange (pPowerObj->mRootPort, reinterpret_cast<long> (pMessageArgument));
+ IOAllowPowerChange(pPowerObj->mRootPort, reinterpret_cast<long>(pMessageArgument));
break;
}
case kIOMessageSystemWillPowerOn:
@@ -135,7 +135,7 @@ void HostPowerServiceDarwin::powerChangeNotificationHandler (void *pvData, io_se
case kIOMessageSystemHasPoweredOn:
{
/* System has finished the wake up process. */
- pPowerObj->notify (HostPowerEvent_Resume);
+ pPowerObj->notify(Reason_HostResume);
break;
}
default:
@@ -143,11 +143,11 @@ void HostPowerServiceDarwin::powerChangeNotificationHandler (void *pvData, io_se
}
}
-void HostPowerServiceDarwin::lowPowerHandler (void *pvData)
+void HostPowerServiceDarwin::lowPowerHandler(void *pvData)
{
- HostPowerServiceDarwin *pPowerObj = static_cast<HostPowerServiceDarwin *> (pvData);
+ HostPowerServiceDarwin *pPowerObj = static_cast<HostPowerServiceDarwin *>(pvData);
- /* Following role for sending the BatteryLow event (5% is critical):
+ /* Following role for sending the BatteryLow event(5% is critical):
* - Not at VM start even if the battery is in an critical state already.
* - When the power cord is removed so the power supply change from AC to
* battery & the battery is in an critical state nothing is triggered.
@@ -156,15 +156,15 @@ void HostPowerServiceDarwin::lowPowerHandler (void *pvData)
* changed from normal to critical. The state transition from critical to
* normal triggers nothing. */
bool fCriticalStateChanged = false;
- pPowerObj->checkBatteryCriticalLevel (&fCriticalStateChanged);
+ pPowerObj->checkBatteryCriticalLevel(&fCriticalStateChanged);
if (fCriticalStateChanged)
- pPowerObj->notify (HostPowerEvent_BatteryLow);
+ pPowerObj->notify(Reason_HostBatteryLow);
}
-void HostPowerServiceDarwin::checkBatteryCriticalLevel (bool *pfCriticalChanged)
+void HostPowerServiceDarwin::checkBatteryCriticalLevel(bool *pfCriticalChanged)
{
CFTypeRef pBlob = IOPSCopyPowerSourcesInfo();
- CFArrayRef pSources = IOPSCopyPowerSourcesList (pBlob);
+ CFArrayRef pSources = IOPSCopyPowerSourcesList(pBlob);
CFDictionaryRef pSource = NULL;
const void *psValue;
@@ -172,30 +172,30 @@ void HostPowerServiceDarwin::checkBatteryCriticalLevel (bool *pfCriticalChanged)
int powerSource = POWER_SOURCE_OUTLET;
bool critical = false;
- if (CFArrayGetCount (pSources) > 0)
+ if (CFArrayGetCount(pSources) > 0)
{
- for (int i = 0; i < CFArrayGetCount (pSources); ++i)
+ for (int i = 0; i < CFArrayGetCount(pSources); ++i)
{
- pSource = IOPSGetPowerSourceDescription (pBlob, CFArrayGetValueAtIndex (pSources, i));
+ pSource = IOPSGetPowerSourceDescription(pBlob, CFArrayGetValueAtIndex(pSources, i));
/* If the source is empty skip over to the next one. */
if (!pSource)
continue;
/* Skip all power sources which are currently not present like a
* second battery. */
- if (CFDictionaryGetValue (pSource, CFSTR (kIOPSIsPresentKey)) == kCFBooleanFalse)
+ if (CFDictionaryGetValue(pSource, CFSTR(kIOPSIsPresentKey)) == kCFBooleanFalse)
continue;
/* Only internal power types are of interest. */
- result = CFDictionaryGetValueIfPresent (pSource, CFSTR (kIOPSTransportTypeKey), &psValue);
+ result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSTransportTypeKey), &psValue);
if (result &&
- CFStringCompare ((CFStringRef)psValue, CFSTR (kIOPSInternalType), 0) == kCFCompareEqualTo)
+ CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSInternalType), 0) == kCFCompareEqualTo)
{
/* First check which power source we are connect on. */
- result = CFDictionaryGetValueIfPresent (pSource, CFSTR (kIOPSPowerSourceStateKey), &psValue);
+ result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSPowerSourceStateKey), &psValue);
if (result &&
- CFStringCompare ((CFStringRef)psValue, CFSTR (kIOPSACPowerValue), 0) == kCFCompareEqualTo)
+ CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSACPowerValue), 0) == kCFCompareEqualTo)
powerSource = POWER_SOURCE_OUTLET;
else if (result &&
- CFStringCompare ((CFStringRef)psValue, CFSTR (kIOPSBatteryPowerValue), 0) == kCFCompareEqualTo)
+ CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSBatteryPowerValue), 0) == kCFCompareEqualTo)
powerSource = POWER_SOURCE_BATTERY;
int curCapacity = 0;
@@ -203,22 +203,22 @@ void HostPowerServiceDarwin::checkBatteryCriticalLevel (bool *pfCriticalChanged)
float remCapacity = 0.0f;
/* Fetch the current capacity value of the power source */
- result = CFDictionaryGetValueIfPresent (pSource, CFSTR (kIOPSCurrentCapacityKey), &psValue);
+ result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSCurrentCapacityKey), &psValue);
if (result)
- CFNumberGetValue ((CFNumberRef)psValue, kCFNumberSInt32Type, &curCapacity);
+ CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &curCapacity);
/* Fetch the maximum capacity value of the power source */
- result = CFDictionaryGetValueIfPresent (pSource, CFSTR (kIOPSMaxCapacityKey), &psValue);
+ result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSMaxCapacityKey), &psValue);
if (result)
- CFNumberGetValue ((CFNumberRef)psValue, kCFNumberSInt32Type, &maxCapacity);
+ CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &maxCapacity);
/* Calculate the remaining capacity in percent */
remCapacity = ((float)curCapacity/(float)maxCapacity * 100.0);
/* Check for critical. 5 percent is default. */
int criticalValue = 5;
- result = CFDictionaryGetValueIfPresent (pSource, CFSTR (kIOPSDeadWarnLevelKey), &psValue);
+ result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSDeadWarnLevelKey), &psValue);
if (result)
- CFNumberGetValue ((CFNumberRef)psValue, kCFNumberSInt32Type, &criticalValue);
+ CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &criticalValue);
critical = (remCapacity < criticalValue);
/* We have to take action only if we are on battery, the
* previous state wasn't critical, the state has changed & the
@@ -228,14 +228,14 @@ void HostPowerServiceDarwin::checkBatteryCriticalLevel (bool *pfCriticalChanged)
mCritical != critical &&
pfCriticalChanged)
*pfCriticalChanged = true;
- Log (("checkBatteryCriticalLevel: Remains: %d.%d%% Critical: %d Critical State Changed: %d\n", (int)remCapacity, (int)(remCapacity * 10) % 10, critical, pfCriticalChanged?*pfCriticalChanged:-1));
+ Log(("checkBatteryCriticalLevel: Remains: %d.%d%% Critical: %d Critical State Changed: %d\n", (int)remCapacity, (int)(remCapacity * 10) % 10, critical, pfCriticalChanged?*pfCriticalChanged:-1));
}
}
}
/* Save the new state */
mCritical = critical;
- CFRelease (pBlob);
- CFRelease (pSources);
+ CFRelease(pBlob);
+ CFRelease(pSources);
}
diff --git a/src/VBox/Main/src-server/darwin/NetIf-darwin.cpp b/src/VBox/Main/src-server/darwin/NetIf-darwin.cpp
index 99cf52e2..cfde818e 100644
--- a/src/VBox/Main/src-server/darwin/NetIf-darwin.cpp
+++ b/src/VBox/Main/src-server/darwin/NetIf-darwin.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -85,7 +85,7 @@ int NetIfList(std::list <ComObjPtr<HostNetworkInterface> > &list)
memcpy(pNew->szName, pEtherNICs->szName, cbNameLen);
struct ifreq IfReq;
- strcpy(IfReq.ifr_name, pNew->szShortName);
+ RTStrCopy(IfReq.ifr_name, sizeof(IfReq.ifr_name), pNew->szShortName);
if (ioctl(sock, SIOCGIFFLAGS, &IfReq) < 0)
{
Log(("NetIfList: ioctl(SIOCGIFFLAGS) -> %d\n", errno));
@@ -391,7 +391,7 @@ int NetIfList(std::list <ComObjPtr<HostNetworkInterface> > &list)
if (pSdl->sdl_type == IFT_ETHER)
{
struct ifreq IfReq;
- strcpy(IfReq.ifr_name, pNew->szShortName);
+ RTStrCopy(IfReq.ifr_name, sizeof(IfReq.ifr_name), pNew->szShortName);
if (ioctl(sock, SIOCGIFFLAGS, &IfReq) < 0)
{
Log(("NetIfList: ioctl(SIOCGIFFLAGS) -> %d\n", errno));
@@ -401,7 +401,7 @@ int NetIfList(std::list <ComObjPtr<HostNetworkInterface> > &list)
pNew->enmStatus = (IfReq.ifr_flags & IFF_UP) ? NETIF_S_UP : NETIF_S_DOWN;
HostNetworkInterfaceType_T enmType;
- if (strncmp("vboxnet", pNew->szName, 7))
+ if (strncmp(pNew->szName, RT_STR_TUPLE("vboxnet")))
enmType = HostNetworkInterfaceType_Bridged;
else
enmType = HostNetworkInterfaceType_HostOnly;
@@ -511,7 +511,7 @@ int NetIfGetConfigByName(PNETIFINFO pInfo)
pInfo->Uuid = uuid;
struct ifreq IfReq;
- strcpy(IfReq.ifr_name, pInfo->szShortName);
+ RTStrCopy(IfReq.ifr_name, sizeof(IfReq.ifr_name), pInfo->szShortName);
if (ioctl(sock, SIOCGIFFLAGS, &IfReq) < 0)
{
Log(("NetIfList: ioctl(SIOCGIFFLAGS) -> %d\n", errno));
@@ -528,4 +528,17 @@ int NetIfGetConfigByName(PNETIFINFO pInfo)
return rc;
}
+/**
+ * Retrieve the physical link speed in megabits per second. If the interface is
+ * not up or otherwise unavailable the zero speed is returned.
+ *
+ * @returns VBox status code.
+ *
+ * @param pcszIfName Interface name.
+ * @param puMbits Where to store the link speed.
+ */
+int NetIfGetLinkSpeed(const char * /*pcszIfName*/, uint32_t * /*puMbits*/)
+{
+ return VERR_NOT_IMPLEMENTED;
+}
#endif
diff --git a/src/VBox/Main/src-server/darwin/PerformanceDarwin.cpp b/src/VBox/Main/src-server/darwin/PerformanceDarwin.cpp
index e3daa585..ea040bd0 100644
--- a/src/VBox/Main/src-server/darwin/PerformanceDarwin.cpp
+++ b/src/VBox/Main/src-server/darwin/PerformanceDarwin.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -24,7 +24,9 @@
#include <sys/errno.h>
#include <iprt/err.h>
#include <iprt/log.h>
+#include <iprt/mp.h>
#include <iprt/param.h>
+#include <iprt/system.h>
#include "Performance.h"
/* The following declarations are missing in 10.4.x SDK */
@@ -63,7 +65,8 @@ public:
virtual int getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total);
virtual int getProcessMemoryUsage(RTPROCESS process, ULONG *used);
private:
- ULONG totalRAM;
+ ULONG totalRAM;
+ uint32_t nCpus;
};
CollectorHAL *createHAL()
@@ -73,19 +76,19 @@ CollectorHAL *createHAL()
CollectorDarwin::CollectorDarwin()
{
- uint64_t hostMemory;
- int mib[2];
- size_t size;
-
- mib[0] = CTL_HW;
- mib[1] = HW_MEMSIZE;
-
- size = sizeof(hostMemory);
- if (sysctl(mib, 2, &hostMemory, &size, NULL, 0) == -1) {
- Log(("sysctl() -> %s", strerror(errno)));
- hostMemory = 0;
+ uint64_t cb;
+ int rc = RTSystemQueryTotalRam(&cb);
+ if (RT_FAILURE(rc))
+ totalRAM = 0;
+ else
+ totalRAM = (ULONG)(cb / 1024);
+ nCpus = RTMpGetOnlineCount();
+ Assert(nCpus);
+ if (nCpus == 0)
+ {
+ /* It is rather unsual to have no CPUs, but the show must go on. */
+ nCpus = 1;
}
- totalRAM = (ULONG)(hostMemory / 1024);
}
int CollectorDarwin::getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle)
@@ -112,23 +115,16 @@ int CollectorDarwin::getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_
int CollectorDarwin::getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available)
{
- kern_return_t krc;
- mach_msg_type_number_t count;
- vm_statistics_data_t info;
-
- count = HOST_VM_INFO_COUNT;
-
- krc = host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&info, &count);
- if (krc != KERN_SUCCESS)
+ AssertReturn(totalRAM, VERR_INTERNAL_ERROR);
+ uint64_t cb;
+ int rc = RTSystemQueryAvailableRam(&cb);
+ if (RT_SUCCESS(rc))
{
- Log(("host_statistics() -> %s", mach_error_string(krc)));
- return RTErrConvertFromDarwinKern(krc);
+ *total = totalRAM;
+ *available = cb / 1024;
+ *used = *total - *available;
}
-
- *total = totalRAM;
- *available = info.free_count * (PAGE_SIZE / 1024);
- *used = *total - *available;
- return VINF_SUCCESS;
+ return rc;
}
static int getProcessInfo(RTPROCESS process, struct proc_taskinfo *tinfo)
@@ -156,8 +152,12 @@ int CollectorDarwin::getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uin
int rc = getProcessInfo(process, &tinfo);
if (RT_SUCCESS(rc))
{
- *user = tinfo.pti_total_user;
- *kernel = tinfo.pti_total_system;
+ /*
+ * Adjust user and kernel values so 100% is when ALL cores are fully
+ * utilized (see @bugref{6345}).
+ */
+ *user = tinfo.pti_total_user / nCpus;
+ *kernel = tinfo.pti_total_system / nCpus;
*total = mach_absolute_time();
}
return rc;
@@ -175,10 +175,5 @@ int CollectorDarwin::getProcessMemoryUsage(RTPROCESS process, ULONG *used)
return rc;
}
-int getDiskListByFs(const char *name, DiskList& list)
-{
- return VERR_NOT_IMPLEMENTED;
-}
-
}
diff --git a/src/VBox/Main/src-server/darwin/iokit.cpp b/src/VBox/Main/src-server/darwin/iokit.cpp
index 0045e7c0..69c572f2 100644
--- a/src/VBox/Main/src-server/darwin/iokit.cpp
+++ b/src/VBox/Main/src-server/darwin/iokit.cpp
@@ -8,7 +8,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2014 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -373,7 +373,7 @@ static void darwinDumpDictCallback(const void *pvKey, const void *pvValue, void
double rd;
CFIndex iCF;
} u;
- memset(&u, 0, sizeof(u));
+ RT_ZERO(u);
CFNumberType NumType = CFNumberGetType((CFNumberRef)pvValue);
if (CFNumberGetValue((CFNumberRef)pvValue, NumType, &u))
{
@@ -1354,7 +1354,7 @@ PDARWINDVD DarwinGetDVDDrives(void)
if (*pszVendor && *pszProduct)
RTStrPrintf(szName, sizeof(szName), "%s %s (#%u)", pszVendor, pszProduct, i);
else
- RTStrPrintf(szName, sizeof(szName), "%s %s (#%u)", *pszVendor ? pszVendor : pszProduct, i);
+ RTStrPrintf(szName, sizeof(szName), "%s (#%u)", *pszVendor ? pszVendor : pszProduct, i);
break;
}
}
diff --git a/src/VBox/Main/src-server/darwin/iokit.h b/src/VBox/Main/src-server/darwin/iokit.h
index 8cb80a52..ff81b3c7 100644
--- a/src/VBox/Main/src-server/darwin/iokit.h
+++ b/src/VBox/Main/src-server/darwin/iokit.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Main/src-server/freebsd/HostHardwareFreeBSD.cpp b/src/VBox/Main/src-server/freebsd/HostHardwareFreeBSD.cpp
index b654f5a6..c65e47c3 100644
--- a/src/VBox/Main/src-server/freebsd/HostHardwareFreeBSD.cpp
+++ b/src/VBox/Main/src-server/freebsd/HostHardwareFreeBSD.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -31,7 +31,6 @@
#include <iprt/mem.h>
#include <iprt/param.h>
#include <iprt/path.h>
-#include <iprt/thread.h> /* for RTThreadSleep() */
#include <iprt/string.h>
#ifdef RT_OS_FREEBSD
@@ -172,8 +171,8 @@ static int getDVDInfoFromCAM(DriveInfoList *pList, bool *pfSuccess)
struct dev_match_pattern DeviceMatchPattern;
struct dev_match_result *paMatches = NULL;
- memset(&DeviceCCB, 0, sizeof(union ccb));
- memset(&DeviceMatchPattern, 0, sizeof(struct device_match_pattern));
+ RT_ZERO(DeviceCCB);
+ RT_ZERO(DeviceMatchPattern);
/* We want to get all devices. */
DeviceCCB.ccb_h.func_code = XPT_DEV_MATCH;
@@ -236,9 +235,9 @@ static int getDVDInfoFromCAM(DriveInfoList *pList, bool *pfSuccess)
struct periph_match_result *pPeriphResult = NULL;
unsigned iPeriphMatch = 0;
- memset(&PeriphCCB, 0, sizeof(union ccb));
- memset(&PeriphMatchPattern, 0, sizeof(struct dev_match_pattern));
- memset(aPeriphMatches, 0, sizeof(aPeriphMatches));
+ RT_ZERO(PeriphCCB);
+ RT_ZERO(PeriphMatchPattern);
+ RT_ZERO(aPeriphMatches);
/* This time we only want the specific nodes for the device. */
PeriphCCB.ccb_h.func_code = XPT_DEV_MATCH;
diff --git a/src/VBox/Main/src-server/freebsd/NetIf-freebsd.cpp b/src/VBox/Main/src-server/freebsd/NetIf-freebsd.cpp
index 7066dab9..049aaaf6 100644
--- a/src/VBox/Main/src-server/freebsd/NetIf-freebsd.cpp
+++ b/src/VBox/Main/src-server/freebsd/NetIf-freebsd.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -43,6 +43,7 @@
#include <net/if_dl.h>
#include <netinet/in.h>
+#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
@@ -271,7 +272,7 @@ int NetIfList(std::list <ComObjPtr<HostNetworkInterface> > &list)
if (pSdl->sdl_type == IFT_ETHER || pSdl->sdl_type == IFT_L2VLAN)
{
struct ifreq IfReq;
- strcpy(IfReq.ifr_name, pNew->szShortName);
+ RTStrCopy(IfReq.ifr_name, sizeof(IfReq.ifr_name), pNew->szShortName);
if (ioctl(sock, SIOCGIFFLAGS, &IfReq) < 0)
{
Log(("NetIfList: ioctl(SIOCGIFFLAGS) -> %d\n", errno));
@@ -281,7 +282,7 @@ int NetIfList(std::list <ComObjPtr<HostNetworkInterface> > &list)
pNew->enmStatus = (IfReq.ifr_flags & IFF_UP) ? NETIF_S_UP : NETIF_S_DOWN;
HostNetworkInterfaceType_T enmType;
- if (strncmp("vboxnet", pNew->szName, 7))
+ if (strncmp(pNew->szName, RT_STR_TUPLE("vboxnet")))
enmType = HostNetworkInterfaceType_Bridged;
else
enmType = HostNetworkInterfaceType_HostOnly;
@@ -388,7 +389,7 @@ int NetIfGetConfigByName(PNETIFINFO pInfo)
pInfo->Uuid = uuid;
struct ifreq IfReq;
- strcpy(IfReq.ifr_name, pInfo->szShortName);
+ RTStrCopy(IfReq.ifr_name, sizeof(IfReq.ifr_name), pInfo->szShortName);
if (ioctl(sock, SIOCGIFFLAGS, &IfReq) < 0)
{
Log(("NetIfList: ioctl(SIOCGIFFLAGS) -> %d\n", errno));
@@ -405,3 +406,16 @@ int NetIfGetConfigByName(PNETIFINFO pInfo)
return rc;
}
+/**
+ * Retrieve the physical link speed in megabits per second. If the interface is
+ * not up or otherwise unavailable the zero speed is returned.
+ *
+ * @returns VBox status code.
+ *
+ * @param pcszIfName Interface name.
+ * @param puMbits Where to store the link speed.
+ */
+int NetIfGetLinkSpeed(const char * /*pcszIfName*/, uint32_t * /*puMbits*/)
+{
+ return VERR_NOT_IMPLEMENTED;
+}
diff --git a/src/VBox/Main/src-server/freebsd/PerformanceFreeBSD.cpp b/src/VBox/Main/src-server/freebsd/PerformanceFreeBSD.cpp
index 0b817842..6770c75b 100644
--- a/src/VBox/Main/src-server/freebsd/PerformanceFreeBSD.cpp
+++ b/src/VBox/Main/src-server/freebsd/PerformanceFreeBSD.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008-2009 Oracle Corporation
+ * Copyright (C) 2008-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -39,7 +39,7 @@ CollectorHAL *createHAL()
int CollectorFreeBSD::getHostCpuLoad(ULONG *user, ULONG *kernel, ULONG *idle)
{
- return E_NOTIMPL;
+ return VERR_NOT_IMPLEMENTED;
}
int CollectorFreeBSD::getHostCpuMHz(ULONG *mhz)
@@ -101,12 +101,17 @@ int CollectorFreeBSD::getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *avail
int CollectorFreeBSD::getProcessCpuLoad(RTPROCESS process, ULONG *user, ULONG *kernel)
{
- return E_NOTIMPL;
+ return VERR_NOT_IMPLEMENTED;
}
int CollectorFreeBSD::getProcessMemoryUsage(RTPROCESS process, ULONG *used)
{
- return E_NOTIMPL;
+ return VERR_NOT_IMPLEMENTED;
+}
+
+int getDiskListByFs(const char *name, DiskList& list)
+{
+ return VERR_NOT_IMPLEMENTED;
}
} /* namespace pm */
diff --git a/src/VBox/Main/src-server/freebsd/USBProxyServiceFreeBSD.cpp b/src/VBox/Main/src-server/freebsd/USBProxyServiceFreeBSD.cpp
index ef8856a3..98535312 100644
--- a/src/VBox/Main/src-server/freebsd/USBProxyServiceFreeBSD.cpp
+++ b/src/VBox/Main/src-server/freebsd/USBProxyServiceFreeBSD.cpp
@@ -266,7 +266,7 @@ PUSBDEVICE USBProxyServiceFreeBSD::getDevices(void)
LogFlowFunc((": %s opened successfully\n", pszDevicePath));
struct usb_device_info UsbDevInfo;
- memset(&UsbDevInfo, 0, sizeof(struct usb_device_info));
+ RT_ZERO(UsbDevInfo);
rc = ioctl(FileUsb, USB_GET_DEVICEINFO, &UsbDevInfo);
if (rc < 0)
diff --git a/src/VBox/Main/src-server/generic/AutostartDb-generic.cpp b/src/VBox/Main/src-server/generic/AutostartDb-generic.cpp
index 923e75fe..07aafe23 100644
--- a/src/VBox/Main/src-server/generic/AutostartDb-generic.cpp
+++ b/src/VBox/Main/src-server/generic/AutostartDb-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009-2010 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -78,7 +78,7 @@ int AutostartDb::autostartModifyDb(bool fAutostart, bool fAddVM)
char abBuf[16 + 1]; /* trailing \0 */
uint32_t cAutostartVms = 0;
- memset(abBuf, 0, sizeof(abBuf));
+ RT_ZERO(abBuf);
/* Check if the file was just created. */
if (cbFile)
diff --git a/src/VBox/Main/src-server/generic/NetIf-generic.cpp b/src/VBox/Main/src-server/generic/NetIf-generic.cpp
index fdf72d6f..2f99585b 100644
--- a/src/VBox/Main/src-server/generic/NetIf-generic.cpp
+++ b/src/VBox/Main/src-server/generic/NetIf-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009-2010 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -21,6 +21,15 @@
#include <iprt/env.h>
#include <iprt/path.h>
#include <iprt/param.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <errno.h>
+#include <unistd.h>
+
+#if defined(RT_OS_SOLARIS)
+# include <sys/sockio.h>
+#endif
#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN)
# include <cstdio>
@@ -218,6 +227,11 @@ int NetIfCreateHostOnlyNetworkInterface(VirtualBox *pVBox,
char szBuf[128]; /* We are not interested in long error messages. */
if (fgets(szBuf, sizeof(szBuf), fp))
{
+ /* Remove trailing new line characters. */
+ char *pLast = szBuf + strlen(szBuf) - 1;
+ if (pLast >= szBuf && *pLast == '\n')
+ *pLast = 0;
+
if (!strncmp(VBOXNETADPCTL_NAME ":", szBuf, sizeof(VBOXNETADPCTL_NAME)))
{
progress->notifyComplete(E_FAIL,
@@ -227,9 +241,6 @@ int NetIfCreateHostOnlyNetworkInterface(VirtualBox *pVBox,
pclose(fp);
return E_FAIL;
}
- char *pLast = szBuf + strlen(szBuf) - 1;
- if (pLast >= szBuf && *pLast == '\n')
- *pLast = 0;
size_t cbNameLen = strlen(szBuf) + 1;
PNETIFINFO pInfo = (PNETIFINFO)RTMemAllocZ(RT_OFFSETOF(NETIFINFO, szName[cbNameLen]));
@@ -307,7 +318,7 @@ int NetIfRemoveHostOnlyNetworkInterface(VirtualBox *pVBox, IN_GUID aId,
ComPtr<IHost> host;
int rc = VINF_SUCCESS;
HRESULT hr = pVBox->COMGETTER(Host)(host.asOutParam());
- if(SUCCEEDED(hr))
+ if (SUCCEEDED(hr))
{
Bstr ifname;
ComPtr<IHostNetworkInterface> iface;
@@ -320,7 +331,7 @@ int NetIfRemoveHostOnlyNetworkInterface(VirtualBox *pVBox, IN_GUID aId,
rc = progress->init(pVBox, host,
Bstr("Removing host network interface").raw(),
FALSE /* aCancelable */);
- if(SUCCEEDED(rc))
+ if (SUCCEEDED(rc))
{
progress.queryInterfaceTo(aProgress);
rc = NetIfAdpCtl(Utf8Str(ifname).c_str(), "remove", NULL, NULL);
@@ -352,8 +363,34 @@ int NetIfGetConfig(HostNetworkInterface * /* pIf */, NETIFINFO *)
return VERR_NOT_IMPLEMENTED;
}
-int NetIfDhcpRediscover(VirtualBox * /* pVbox */, HostNetworkInterface * /* pIf */)
+int NetIfDhcpRediscover(VirtualBox * /* pVBox */, HostNetworkInterface * /* pIf */)
{
return VERR_NOT_IMPLEMENTED;
}
+/**
+ * Obtain the current state of the interface.
+ *
+ * @returns VBox status code.
+ *
+ * @param pcszIfName Interface name.
+ * @param penmState Where to store the retrieved state.
+ */
+int NetIfGetState(const char *pcszIfName, NETIFSTATUS *penmState)
+{
+ int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+ if (sock < 0)
+ return VERR_OUT_OF_RESOURCES;
+ struct ifreq Req;
+ RT_ZERO(Req);
+ RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pcszIfName);
+ if (ioctl(sock, SIOCGIFFLAGS, &Req) < 0)
+ {
+ Log(("NetIfGetState: ioctl(SIOCGIFFLAGS) -> %d\n", errno));
+ *penmState = NETIF_S_UNKNOWN;
+ }
+ else
+ *penmState = (Req.ifr_flags & IFF_UP) ? NETIF_S_UP : NETIF_S_DOWN;
+ close(sock);
+ return VINF_SUCCESS;
+}
diff --git a/src/VBox/Main/src-server/linux/HostDnsServiceLinux.cpp b/src/VBox/Main/src-server/linux/HostDnsServiceLinux.cpp
new file mode 100644
index 00000000..89de18df
--- /dev/null
+++ b/src/VBox/Main/src-server/linux/HostDnsServiceLinux.cpp
@@ -0,0 +1,233 @@
+/* $Id: HostDnsServiceLinux.cpp $ */
+/** @file
+ * Linux specific DNS information fetching.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/initterm.h>
+#include <iprt/file.h>
+#include <iprt/log.h>
+#include <iprt/stream.h>
+#include <iprt/string.h>
+#include <iprt/semaphore.h>
+#include <iprt/thread.h>
+
+#include <errno.h>
+#include <poll.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <fcntl.h>
+
+#include <linux/limits.h>
+
+#include <sys/inotify.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <string>
+#include <vector>
+#include "../HostDnsService.h"
+
+
+static int g_DnsMonitorStop[2];
+
+static const std::string g_EtcFolder = "/etc";
+static const std::string g_ResolvConf = "resolv.conf";
+static const std::string g_ResolvConfFullPath = "/etc/resolv.conf";
+
+class FileDescriptor
+{
+ public:
+ FileDescriptor(int d = -1):fd(d){}
+
+ virtual ~FileDescriptor() {
+ if (fd != -1)
+ close(fd);
+ }
+
+ int fileDescriptor() const {return fd;}
+
+ protected:
+ int fd;
+};
+
+
+class AutoNotify:public FileDescriptor
+{
+ public:
+ AutoNotify()
+ {
+ FileDescriptor::fd = inotify_init();
+ AssertReturnVoid(FileDescriptor::fd != -1);
+ }
+};
+
+struct InotifyEventWithName
+{
+ struct inotify_event e;
+ char name[NAME_MAX];
+};
+
+HostDnsServiceLinux::~HostDnsServiceLinux()
+{
+ monitorThreadShutdown();
+}
+
+
+int HostDnsServiceLinux::monitorWorker()
+{
+
+ AutoNotify a;
+
+ int rc = socketpair(AF_LOCAL, SOCK_DGRAM, 0, g_DnsMonitorStop);
+ AssertMsgReturn(rc == 0, ("socketpair: failed (%d: %s)\n", errno, strerror(errno)), E_FAIL);
+
+ FileDescriptor stopper0(g_DnsMonitorStop[0]);
+ FileDescriptor stopper1(g_DnsMonitorStop[1]);
+
+ pollfd polls[2];
+ RT_ZERO(polls);
+
+ polls[0].fd = a.fileDescriptor();
+ polls[0].events = POLLIN;
+
+ polls[1].fd = g_DnsMonitorStop[1];
+ polls[1].events = POLLIN;
+
+ monitorThreadInitializationDone();
+
+ int wd[2];
+ wd[0] = wd[1] = -1;
+ /* inotify inialization */
+ wd[0] = inotify_add_watch(a.fileDescriptor(),
+ g_ResolvConfFullPath.c_str(), IN_CLOSE_WRITE|IN_DELETE_SELF);
+
+ /**
+ * If /etc/resolv.conf exists we want to listen for movements: because
+ * # mv /etc/resolv.conf ...
+ * won't arm IN_DELETE_SELF on wd[0] instead it will fire IN_MOVE_FROM on wd[1].
+ *
+ * Because on some distributions /etc/resolv.conf is link, wd[0] can't detect deletion,
+ * it's recognizible on directory level (wd[1]) only.
+ */
+ wd[1] = inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
+ wd[0] == -1 ? IN_MOVED_TO|IN_CREATE : IN_MOVED_FROM|IN_DELETE);
+
+ struct InotifyEventWithName combo;
+ while(true)
+ {
+ rc = poll(polls, 2, -1);
+ if (rc == -1)
+ continue;
+
+ AssertMsgReturn( ((polls[0].revents & (POLLERR|POLLNVAL)) == 0)
+ && ((polls[1].revents & (POLLERR|POLLNVAL)) == 0),
+ ("Debug Me"), VERR_INTERNAL_ERROR);
+
+ if (polls[1].revents & POLLIN)
+ return VINF_SUCCESS; /* time to shutdown */
+
+ if (polls[0].revents & POLLIN)
+ {
+ RT_ZERO(combo);
+ ssize_t r = read(polls[0].fd, static_cast<void *>(&combo), sizeof(combo));
+
+ if (combo.e.wd == wd[0])
+ {
+ if (combo.e.mask & IN_CLOSE_WRITE)
+ {
+ readResolvConf();
+ /* notifyAll() takes required locks */
+ notifyAll();
+ }
+ else if (combo.e.mask & IN_DELETE_SELF)
+ {
+ inotify_rm_watch(a.fileDescriptor(), wd[0]); /* removes file watcher */
+ inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
+ IN_MOVED_TO|IN_CREATE); /* alter folder watcher */
+ }
+ else if (combo.e.mask & IN_IGNORED)
+ {
+ wd[0] = -1; /* we want receive any events on this watch */
+ }
+ else
+ {
+ /**
+ * It shouldn't happen, in release we will just ignore in debug
+ * we will have to chance to look at into inotify_event
+ */
+ AssertMsgFailed(("Debug Me!!!"));
+ }
+ }
+ else if (combo.e.wd == wd[1])
+ {
+ if ( combo.e.mask & IN_MOVED_FROM
+ || combo.e.mask & IN_DELETE)
+ {
+ if (g_ResolvConf == combo.e.name)
+ {
+ /**
+ * Our file has been moved so we should change watching mode.
+ */
+ inotify_rm_watch(a.fileDescriptor(), wd[0]);
+ wd[1] = inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
+ IN_MOVED_TO|IN_CREATE);
+ AssertMsg(wd[1] != -1,
+ ("It shouldn't happen, further investigation is needed\n"));
+ }
+ }
+ else
+ {
+ AssertMsg(combo.e.mask & (IN_MOVED_TO|IN_CREATE),
+ ("%RX32 event isn't expected, we are waiting for IN_MOVED|IN_CREATE\n",
+ combo.e.mask));
+ if (g_ResolvConf == combo.e.name)
+ {
+ AssertMsg(wd[0] == -1, ("We haven't removed file watcher first\n"));
+
+ /* alter folder watcher*/
+ wd[1] = inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
+ IN_MOVED_FROM|IN_DELETE);
+ AssertMsg(wd[1] != -1, ("It shouldn't happen.\n"));
+
+ wd[0] = inotify_add_watch(a.fileDescriptor(),
+ g_ResolvConfFullPath.c_str(),
+ IN_CLOSE_WRITE | IN_DELETE_SELF);
+ AssertMsg(wd[0] != -1, ("Adding watcher to file (%s) has been failed!\n",
+ g_ResolvConfFullPath.c_str()));
+
+ /* Notify our listeners */
+ readResolvConf();
+ notifyAll();
+
+ }
+ }
+ }
+ else
+ {
+ /* It shouldn't happen */
+ AssertMsgFailed(("Shouldn't happen! Please debug me!"));
+ }
+ }
+ }
+}
+
+
+void HostDnsServiceLinux::monitorThreadShutdown()
+{
+ send(g_DnsMonitorStop[0], "", 1, 0);
+}
diff --git a/src/VBox/Main/src-server/linux/HostHardwareLinux.cpp b/src/VBox/Main/src-server/linux/HostHardwareLinux.cpp
index 2dc722cc..1ff26d81 100644
--- a/src/VBox/Main/src-server/linux/HostHardwareLinux.cpp
+++ b/src/VBox/Main/src-server/linux/HostHardwareLinux.cpp
@@ -6,7 +6,7 @@
*/
/*
- * Copyright (C) 2008-2010 Oracle Corporation
+ * Copyright (C) 2008-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -37,7 +37,6 @@
#include <iprt/param.h>
#include <iprt/path.h>
#include <iprt/string.h>
-#include <iprt/thread.h> /* for RTThreadSleep() */
#include <linux/cdrom.h>
#include <linux/fd.h>
@@ -1282,7 +1281,7 @@ hotplugInotifyImpl::hotplugInotifyImpl(const char *pcszDevicesRoot) :
break;
if (RT_FAILURE(rc = pipeCreateSimple(&mhWakeupPipeR, &mhWakeupPipeW)))
break;
- } while(0);
+ } while (0);
mStatus = rc;
if (RT_FAILURE(rc))
term();
diff --git a/src/VBox/Main/src-server/linux/NetIf-linux.cpp b/src/VBox/Main/src-server/linux/NetIf-linux.cpp
index 6fe799cf..2384cc52 100644
--- a/src/VBox/Main/src-server/linux/NetIf-linux.cpp
+++ b/src/VBox/Main/src-server/linux/NetIf-linux.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -37,14 +37,23 @@
#include "netif.h"
#include "Logging.h"
+/**
+ * Obtain the name of the interface used for default routing.
+ *
+ * NOTE: There is a copy in Devices/Network/testcase/tstIntNet-1.cpp.
+ *
+ * @returns VBox status code.
+ *
+ * @param pszName The buffer of IFNAMSIZ+1 length where to put the name.
+ */
static int getDefaultIfaceName(char *pszName)
{
FILE *fp = fopen("/proc/net/route", "r");
char szBuf[1024];
char szIfName[17];
- char szAddr[129];
- char szGateway[129];
- char szMask[129];
+ uint32_t uAddr;
+ uint32_t uGateway;
+ uint32_t uMask;
int iTmp;
unsigned uFlags;
@@ -52,13 +61,13 @@ static int getDefaultIfaceName(char *pszName)
{
while (fgets(szBuf, sizeof(szBuf)-1, fp))
{
- int n = sscanf(szBuf, "%16s %128s %128s %X %d %d %d %128s %d %d %d\n",
- szIfName, szAddr, szGateway, &uFlags, &iTmp, &iTmp, &iTmp,
- szMask, &iTmp, &iTmp, &iTmp);
+ int n = sscanf(szBuf, "%16s %x %x %x %d %d %d %x %d %d %d\n",
+ szIfName, &uAddr, &uGateway, &uFlags, &iTmp, &iTmp, &iTmp,
+ &uMask, &iTmp, &iTmp, &iTmp);
if (n < 10 || !(uFlags & RTF_UP))
continue;
- if (strcmp(szAddr, "00000000") == 0 && strcmp(szMask, "00000000") == 0)
+ if (uAddr == 0 && uMask == 0)
{
fclose(fp);
strncpy(pszName, szIfName, 16);
@@ -71,14 +80,55 @@ static int getDefaultIfaceName(char *pszName)
return VERR_INTERNAL_ERROR;
}
+static uint32_t getInterfaceSpeed(const char *pszName)
+{
+ /*
+ * I wish I could do simple ioctl here, but older kernels require root
+ * privileges for any ethtool commands.
+ */
+ char szBuf[256];
+ uint32_t uSpeed = 0;
+ /* First, we try to retrieve the speed via sysfs. */
+ RTStrPrintf(szBuf, sizeof(szBuf), "/sys/class/net/%s/speed", pszName);
+ FILE *fp = fopen(szBuf, "r");
+ if (fp)
+ {
+ if (fscanf(fp, "%u", &uSpeed) != 1)
+ uSpeed = 0;
+ fclose(fp);
+ }
+ if (uSpeed == 10)
+ {
+ /* Check the cable is plugged in at all */
+ unsigned uCarrier = 0;
+ RTStrPrintf(szBuf, sizeof(szBuf), "/sys/class/net/%s/carrier", pszName);
+ fp = fopen(szBuf, "r");
+ if (fp)
+ {
+ if (fscanf(fp, "%u", &uCarrier) != 1 || uCarrier == 0)
+ uSpeed = 0;
+ fclose(fp);
+ }
+ }
+
+ if (uSpeed == 0)
+ {
+ /* Failed to get speed via sysfs, go to plan B. */
+ int rc = NetIfAdpCtlOut(pszName, "speed", szBuf, sizeof(szBuf));
+ if (RT_SUCCESS(rc))
+ uSpeed = RTStrToUInt32(szBuf);
+ }
+ return uSpeed;
+}
+
static int getInterfaceInfo(int iSocket, const char *pszName, PNETIFINFO pInfo)
{
// Zeroing out pInfo is a bad idea as it should contain both short and long names at
// this point. So make sure the structure is cleared by the caller if necessary!
// memset(pInfo, 0, sizeof(*pInfo));
struct ifreq Req;
- memset(&Req, 0, sizeof(Req));
- strncpy(Req.ifr_name, pszName, sizeof(Req.ifr_name) - 1);
+ RT_ZERO(Req);
+ RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pszName);
if (ioctl(iSocket, SIOCGIFHWADDR, &Req) >= 0)
{
switch (Req.ifr_hwaddr.sa_family)
@@ -122,7 +172,7 @@ static int getInterfaceInfo(int iSocket, const char *pszName, PNETIFINFO pInfo)
char szName[30];
for (;;)
{
- memset(szName, 0, sizeof(szName));
+ RT_ZERO(szName);
int n = fscanf(fp,
"%08x%08x%08x%08x"
" %02x %02x %02x %02x %20s\n",
@@ -152,31 +202,10 @@ static int getInterfaceInfo(int iSocket, const char *pszName, PNETIFINFO pInfo)
* Don't even try to get speed for non-Ethernet interfaces, it only
* produces errors.
*/
- pInfo->uSpeedMbits = 0;
if (pInfo->enmMediumType == NETIF_T_ETHERNET)
- {
- /*
- * I wish I could do simple ioctl here, but older kernels require root
- * privileges for any ethtool commands.
- */
- char szBuf[256];
- /* First, we try to retrieve the speed via sysfs. */
- RTStrPrintf(szBuf, sizeof(szBuf), "/sys/class/net/%s/speed", pszName);
- fp = fopen(szBuf, "r");
- if (fp)
- {
- if (fscanf(fp, "%u", &pInfo->uSpeedMbits) != 1)
- pInfo->uSpeedMbits = 0;
- fclose(fp);
- }
- if (pInfo->uSpeedMbits == 0)
- {
- /* Failed to get speed via sysfs, go to plan B. */
- int rc = NetIfAdpCtlOut(pszName, "speed", szBuf, sizeof(szBuf));
- if (RT_SUCCESS(rc))
- pInfo->uSpeedMbits = RTStrToUInt32(szBuf);
- }
- }
+ pInfo->uSpeedMbits = getInterfaceSpeed(pszName);
+ else
+ pInfo->uSpeedMbits = 0;
}
return VINF_SUCCESS;
}
@@ -216,7 +245,7 @@ int NetIfList(std::list <ComObjPtr<HostNetworkInterface> > &list)
IfObj.createObject();
HostNetworkInterfaceType_T enmType;
- if (strncmp("vboxnet", pszName, 7))
+ if (strncmp(pszName, RT_STR_TUPLE("vboxnet")))
enmType = HostNetworkInterfaceType_Bridged;
else
enmType = HostNetworkInterfaceType_HostOnly;
@@ -251,3 +280,35 @@ int NetIfGetConfigByName(PNETIFINFO pInfo)
close(sock);
return rc;
}
+
+/**
+ * Retrieve the physical link speed in megabits per second. If the interface is
+ * not up or otherwise unavailable the zero speed is returned.
+ *
+ * @returns VBox status code.
+ *
+ * @param pcszIfName Interface name.
+ * @param puMbits Where to store the link speed.
+ */
+int NetIfGetLinkSpeed(const char *pcszIfName, uint32_t *puMbits)
+{
+ int sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0)
+ return VERR_OUT_OF_RESOURCES;
+ struct ifreq Req;
+ RT_ZERO(Req);
+ RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pcszIfName);
+ if (ioctl(sock, SIOCGIFHWADDR, &Req) >= 0)
+ {
+ if (ioctl(sock, SIOCGIFFLAGS, &Req) >= 0)
+ if (Req.ifr_flags & IFF_UP)
+ {
+ close(sock);
+ *puMbits = getInterfaceSpeed(pcszIfName);
+ return VINF_SUCCESS;
+ }
+ }
+ close(sock);
+ *puMbits = 0;
+ return VWRN_NOT_FOUND;
+}
diff --git a/src/VBox/Main/src-server/linux/PerformanceLinux.cpp b/src/VBox/Main/src-server/linux/PerformanceLinux.cpp
index 4e165ee3..77ccb9b8 100644
--- a/src/VBox/Main/src-server/linux/PerformanceLinux.cpp
+++ b/src/VBox/Main/src-server/linux/PerformanceLinux.cpp
@@ -6,7 +6,7 @@
*/
/*
- * Copyright (C) 2008-2011 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -27,8 +27,11 @@
#include <iprt/ctype.h>
#include <iprt/err.h>
#include <iprt/param.h>
+#include <iprt/path.h>
#include <iprt/string.h>
+#include <iprt/system.h>
#include <iprt/mp.h>
+#include <iprt/linux/sysfs.h>
#include <map>
#include <vector>
@@ -36,6 +39,8 @@
#include "Logging.h"
#include "Performance.h"
+#define VBOXVOLINFO_NAME "VBoxVolInfo"
+
namespace pm {
class CollectorLinux : public CollectorHAL
@@ -45,15 +50,23 @@ public:
virtual int preCollect(const CollectorHints& hints, uint64_t /* iTick */);
virtual int getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available);
virtual int getHostFilesystemUsage(const char *name, ULONG *total, ULONG *used, ULONG *available);
+ virtual int getHostDiskSize(const char *name, uint64_t *size);
virtual int getProcessMemoryUsage(RTPROCESS process, ULONG *used);
virtual int getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle);
virtual int getRawHostNetworkLoad(const char *name, uint64_t *rx, uint64_t *tx);
virtual int getRawHostDiskLoad(const char *name, uint64_t *disk_ms, uint64_t *total_ms);
virtual int getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total);
+
+ virtual int getDiskListByFs(const char *name, DiskList& listUsage, DiskList& listLoad);
private:
virtual int _getRawHostCpuLoad();
int getRawProcessStats(RTPROCESS process, uint64_t *cpuUser, uint64_t *cpuKernel, ULONG *memPagesUsed);
+ void getDiskName(char *pszDiskName, size_t cbDiskName, const char *pszDevName, bool fTrimDigits);
+ void addVolumeDependencies(const char *pcszVolume, DiskList& listDisks);
+ void addRaidDisks(const char *pcszDevice, DiskList& listDisks);
+ char *trimTrailingDigits(char *pszName);
+ char *trimNewline(char *pszName);
struct VMProcessStats
{
@@ -68,6 +81,7 @@ private:
uint64_t mUser, mKernel, mIdle;
uint64_t mSingleUser, mSingleKernel, mSingleIdle;
uint32_t mHZ;
+ ULONG totalRAM;
};
CollectorHAL *createHAL()
@@ -88,6 +102,13 @@ CollectorLinux::CollectorLinux()
else
mHZ = hz;
LogFlowThisFunc(("mHZ=%u\n", mHZ));
+
+ uint64_t cb;
+ int rc = RTSystemQueryTotalRam(&cb);
+ if (RT_FAILURE(rc))
+ totalRAM = 0;
+ else
+ totalRAM = (ULONG)(cb / 1024);
}
int CollectorLinux::preCollect(const CollectorHints& hints, uint64_t /* iTick */)
@@ -190,35 +211,21 @@ int CollectorLinux::getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint
int CollectorLinux::getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available)
{
- int rc = VINF_SUCCESS;
- ULONG buffers, cached;
- FILE *f = fopen("/proc/meminfo", "r");
-
- if (f)
+ AssertReturn(totalRAM, VERR_INTERNAL_ERROR);
+ uint64_t cb;
+ int rc = RTSystemQueryAvailableRam(&cb);
+ if (RT_SUCCESS(rc))
{
- int processed = fscanf(f, "MemTotal: %u kB\n", total);
- processed += fscanf(f, "MemFree: %u kB\n", available);
- processed += fscanf(f, "Buffers: %u kB\n", &buffers);
- processed += fscanf(f, "Cached: %u kB\n", &cached);
- if (processed == 4)
- {
- *available += buffers + cached;
- *used = *total - *available;
- }
- else
- rc = VERR_FILE_IO_ERROR;
- fclose(f);
+ *total = totalRAM;
+ *available = cb / 1024;
+ *used = *total - *available;
}
- else
- rc = VERR_ACCESS_DENIED;
-
return rc;
}
int CollectorLinux::getHostFilesystemUsage(const char *path, ULONG *total, ULONG *used, ULONG *available)
{
struct statvfs stats;
- const unsigned _MB = 1024 * 1024;
if (statvfs(path, &stats) == -1)
{
@@ -226,13 +233,35 @@ int CollectorLinux::getHostFilesystemUsage(const char *path, ULONG *total, ULONG
return VERR_ACCESS_DENIED;
}
uint64_t cbBlock = stats.f_frsize ? stats.f_frsize : stats.f_bsize;
- *total = (ULONG)(cbBlock * stats.f_blocks / _MB);
- *used = (ULONG)(cbBlock * (stats.f_blocks - stats.f_bfree) / _MB);
- *available = (ULONG)(cbBlock * stats.f_bavail / _MB);
+ *total = (ULONG)(cbBlock * stats.f_blocks / _1M);
+ *used = (ULONG)(cbBlock * (stats.f_blocks - stats.f_bfree) / _1M);
+ *available = (ULONG)(cbBlock * stats.f_bavail / _1M);
return VINF_SUCCESS;
}
+int CollectorLinux::getHostDiskSize(const char *pszFile, uint64_t *size)
+{
+ char *pszPath = NULL;
+
+ RTStrAPrintf(&pszPath, "/sys/block/%s/size", pszFile);
+ Assert(pszPath);
+
+ int rc = VINF_SUCCESS;
+ if (!RTLinuxSysFsExists(pszPath))
+ rc = VERR_FILE_NOT_FOUND;
+ else
+ {
+ int64_t cSize = RTLinuxSysFsReadIntFile(0, pszPath);
+ if (cSize < 0)
+ rc = VERR_ACCESS_DENIED;
+ else
+ *size = cSize * 512;
+ }
+ RTStrFree(pszPath);
+ return rc;
+}
+
int CollectorLinux::getProcessMemoryUsage(RTPROCESS process, ULONG *used)
{
VMProcessMap::const_iterator it = mProcessStats.find(process);
@@ -261,9 +290,8 @@ int CollectorLinux::getRawProcessStats(RTPROCESS process, uint64_t *cpuUser, uin
char buf[80]; /* @todo: this should be tied to max allowed proc name. */
RTStrAPrintf(&pszName, "/proc/%d/stat", process);
- //printf("Opening %s...\n", pszName);
FILE *f = fopen(pszName, "r");
- RTMemFree(pszName);
+ RTStrFree(pszName);
if (f)
{
@@ -288,42 +316,35 @@ int CollectorLinux::getRawProcessStats(RTPROCESS process, uint64_t *cpuUser, uin
return rc;
}
-int CollectorLinux::getRawHostNetworkLoad(const char *name, uint64_t *rx, uint64_t *tx)
+int CollectorLinux::getRawHostNetworkLoad(const char *pszFile, uint64_t *rx, uint64_t *tx)
{
- int rc = VINF_SUCCESS;
char szIfName[/*IFNAMSIZ*/ 16 + 36];
- long long unsigned int u64Rx, u64Tx;
- RTStrPrintf(szIfName, sizeof(szIfName), "/sys/class/net/%s/statistics/rx_bytes", name);
- FILE *f = fopen(szIfName, "r");
- if (f)
- {
- if (fscanf(f, "%llu", &u64Rx) == 1)
- *rx = u64Rx;
- else
- rc = VERR_FILE_IO_ERROR;
- fclose(f);
- RTStrPrintf(szIfName, sizeof(szIfName), "/sys/class/net/%s/statistics/tx_bytes", name);
- f = fopen(szIfName, "r");
- if (f)
- {
- if (fscanf(f, "%llu", &u64Tx) == 1)
- *tx = u64Tx;
- else
- rc = VERR_FILE_IO_ERROR;
- fclose(f);
- }
- else
- rc = VERR_ACCESS_DENIED;
- }
- else
- rc = VERR_ACCESS_DENIED;
+ RTStrPrintf(szIfName, sizeof(szIfName), "/sys/class/net/%s/statistics/rx_bytes", pszFile);
+ if (!RTLinuxSysFsExists(szIfName))
+ return VERR_FILE_NOT_FOUND;
- return rc;
+ int64_t cSize = RTLinuxSysFsReadIntFile(0, szIfName);
+ if (cSize < 0)
+ return VERR_ACCESS_DENIED;
+
+ *rx = cSize;
+
+ RTStrPrintf(szIfName, sizeof(szIfName), "/sys/class/net/%s/statistics/tx_bytes", pszFile);
+ if (!RTLinuxSysFsExists(szIfName))
+ return VERR_FILE_NOT_FOUND;
+
+ cSize = RTLinuxSysFsReadIntFile(0, szIfName);
+ if (cSize < 0)
+ return VERR_ACCESS_DENIED;
+
+ *tx = cSize;
+ return VINF_SUCCESS;
}
int CollectorLinux::getRawHostDiskLoad(const char *name, uint64_t *disk_ms, uint64_t *total_ms)
{
+#if 0
int rc = VINF_SUCCESS;
char szIfName[/*IFNAMSIZ*/ 16 + 36];
long long unsigned int u64Busy, tmp;
@@ -344,28 +365,184 @@ int CollectorLinux::getRawHostDiskLoad(const char *name, uint64_t *disk_ms, uint
}
else
rc = VERR_ACCESS_DENIED;
+#else
+ int rc = VERR_MISSING;
+ FILE *f = fopen("/proc/diskstats", "r");
+ if (f)
+ {
+ char szBuf[128];
+ while (fgets(szBuf, sizeof(szBuf), f))
+ {
+ char *pszBufName = szBuf;
+ while (*pszBufName == ' ') ++pszBufName; /* Skip spaces */
+ while (RT_C_IS_DIGIT(*pszBufName)) ++pszBufName; /* Skip major */
+ while (*pszBufName == ' ') ++pszBufName; /* Skip spaces */
+ while (RT_C_IS_DIGIT(*pszBufName)) ++pszBufName; /* Skip minor */
+ while (*pszBufName == ' ') ++pszBufName; /* Skip spaces */
+
+ char *pszBufData = strchr(pszBufName, ' ');
+ if (!pszBufData)
+ {
+ LogRel(("CollectorLinux::getRawHostDiskLoad() failed to parse disk stats: %s\n", szBuf));
+ continue;
+ }
+ *pszBufData++ = '\0';
+ if (!strcmp(name, pszBufName))
+ {
+ long long unsigned int u64Busy, tmp;
+
+ if (sscanf(pszBufData, "%llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu",
+ &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &u64Busy, &tmp) == 11)
+ {
+ *disk_ms = u64Busy;
+ *total_ms = (uint64_t)(mSingleUser + mSingleKernel + mSingleIdle) * 1000 / mHZ;
+ rc = VINF_SUCCESS;
+ }
+ else
+ rc = VERR_FILE_IO_ERROR;
+ break;
+ }
+ }
+ fclose(f);
+ }
+#endif
return rc;
}
-static char *getDiskName(char *pszDiskName, size_t cbDiskName, const char *pszDevName)
+char *CollectorLinux::trimNewline(char *pszName)
+{
+ unsigned cbName = strlen(pszName);
+ if (cbName == 0)
+ return pszName;
+
+ char *pszEnd = pszName + cbName - 1;
+ while (pszEnd > pszName && *pszEnd == '\n')
+ pszEnd--;
+ pszEnd[1] = '\0';
+
+ return pszName;
+}
+
+char *CollectorLinux::trimTrailingDigits(char *pszName)
+{
+ unsigned cbName = strlen(pszName);
+ if (cbName == 0)
+ return pszName;
+
+ char *pszEnd = pszName + cbName - 1;
+ while (pszEnd > pszName && (RT_C_IS_DIGIT(*pszEnd) || *pszEnd == '\n'))
+ pszEnd--;
+ pszEnd[1] = '\0';
+
+ return pszName;
+}
+
+/**
+ * Use the partition name to get the name of the disk. Any path component is stripped.
+ * if fTrimDigits is true, trailing digits are stripped as well, for example '/dev/sda5'
+ * is converted to 'sda'.
+ *
+ * @param pszDiskName Where to store the name of the disk.
+ * @param cbDiskName The size of the buffer pszDiskName points to.
+ * @param pszDevName The device name used to get the disk name.
+ * @param fTrimDigits Trim trailing digits (e.g. /dev/sda5)
+ */
+void CollectorLinux::getDiskName(char *pszDiskName, size_t cbDiskName, const char *pszDevName, bool fTrimDigits)
{
unsigned cbName = 0;
unsigned cbDevName = strlen(pszDevName);
const char *pszEnd = pszDevName + cbDevName - 1;
- while (pszEnd > pszDevName && RT_C_IS_DIGIT(*pszEnd))
- pszEnd--;
+ if (fTrimDigits)
+ while (pszEnd > pszDevName && RT_C_IS_DIGIT(*pszEnd))
+ pszEnd--;
while (pszEnd > pszDevName && *pszEnd != '/')
{
cbName++;
pszEnd--;
}
RTStrCopy(pszDiskName, RT_MIN(cbName + 1, cbDiskName), pszEnd + 1);
- return pszDiskName;
}
+void CollectorLinux::addRaidDisks(const char *pcszDevice, DiskList& listDisks)
+{
+ FILE *f = fopen("/proc/mdstat", "r");
+ if (f)
+ {
+ char szBuf[128];
+ while (fgets(szBuf, sizeof(szBuf), f))
+ {
+ char *pszBufName = szBuf;
-int getDiskListByFs(const char *pszPath, DiskList& listDisks)
+ char *pszBufData = strchr(pszBufName, ' ');
+ if (!pszBufData)
+ {
+ LogRel(("CollectorLinux::addRaidDisks() failed to parse disk stats: %s\n", szBuf));
+ continue;
+ }
+ *pszBufData++ = '\0';
+ if (!strcmp(pcszDevice, pszBufName))
+ {
+ while (*pszBufData == ':') ++pszBufData; /* Skip delimiter */
+ while (*pszBufData == ' ') ++pszBufData; /* Skip spaces */
+ while (RT_C_IS_ALNUM(*pszBufData)) ++pszBufData; /* Skip status */
+ while (*pszBufData == ' ') ++pszBufData; /* Skip spaces */
+ while (RT_C_IS_ALNUM(*pszBufData)) ++pszBufData; /* Skip type */
+
+ while (*pszBufData != '\0')
+ {
+ while (*pszBufData == ' ') ++pszBufData; /* Skip spaces */
+ char *pszDisk = pszBufData;
+ while (RT_C_IS_ALPHA(*pszBufData))
+ ++pszBufData;
+ if (*pszBufData)
+ {
+ *pszBufData++ = '\0';
+ listDisks.push_back(RTCString(pszDisk));
+ while (*pszBufData != '\0' && *pszBufData != ' ')
+ ++pszBufData;
+ }
+ else
+ listDisks.push_back(RTCString(pszDisk));
+ }
+ break;
+ }
+ }
+ fclose(f);
+ }
+}
+
+void CollectorLinux::addVolumeDependencies(const char *pcszVolume, DiskList& listDisks)
+{
+ char szVolInfo[RTPATH_MAX];
+ int rc = RTPathAppPrivateArch(szVolInfo,
+ sizeof(szVolInfo) - sizeof("/" VBOXVOLINFO_NAME " ") - strlen(pcszVolume));
+ if (RT_FAILURE(rc))
+ {
+ LogRel(("VolInfo: Failed to get program path, rc=%Rrc\n", rc));
+ return;
+ }
+ strcat(szVolInfo, "/" VBOXVOLINFO_NAME " ");
+ strcat(szVolInfo, pcszVolume);
+
+ FILE *fp = popen(szVolInfo, "r");
+ if (fp)
+ {
+ char szBuf[128];
+
+ while (fgets(szBuf, sizeof(szBuf), fp))
+ if (strncmp(szBuf, RT_STR_TUPLE("dm-")))
+ listDisks.push_back(RTCString(trimTrailingDigits(szBuf)));
+ else
+ listDisks.push_back(RTCString(trimNewline(szBuf)));
+
+ pclose(fp);
+ }
+ else
+ listDisks.push_back(RTCString(pcszVolume));
+}
+
+int CollectorLinux::getDiskListByFs(const char *pszPath, DiskList& listUsage, DiskList& listLoad)
{
FILE *mtab = setmntent("/etc/mtab", "r");
if (mtab)
@@ -373,10 +550,45 @@ int getDiskListByFs(const char *pszPath, DiskList& listDisks)
struct mntent *mntent;
while ((mntent = getmntent(mtab)))
{
+ /* Skip rootfs entry, there must be another root mount. */
+ if (strcmp(mntent->mnt_fsname, "rootfs") == 0)
+ continue;
if (strcmp(pszPath, mntent->mnt_dir) == 0)
{
- char szDevName[32];
- listDisks.push_back(RTCString(getDiskName(szDevName, sizeof(szDevName), mntent->mnt_fsname)));
+ char szDevName[128];
+ char szFsName[1024];
+ /* Try to resolve symbolic link if necessary. Yes, we access the file system here! */
+ int rc = RTPathReal(mntent->mnt_fsname, szFsName, sizeof(szFsName));
+ if (RT_FAILURE(rc))
+ continue; /* something got wrong, just ignore this path */
+ /* check against the actual mtab entry, NOT the real path as /dev/mapper/xyz is
+ * often a symlink to something else */
+ if (!strncmp(mntent->mnt_fsname, RT_STR_TUPLE("/dev/mapper")))
+ {
+ /* LVM */
+ getDiskName(szDevName, sizeof(szDevName), mntent->mnt_fsname, false /*=fTrimDigits*/);
+ addVolumeDependencies(szDevName, listUsage);
+ listLoad = listUsage;
+ }
+ else if (!strncmp(szFsName, RT_STR_TUPLE("/dev/md")))
+ {
+ /* Software RAID */
+ getDiskName(szDevName, sizeof(szDevName), szFsName, false /*=fTrimDigits*/);
+ listUsage.push_back(RTCString(szDevName));
+ addRaidDisks(szDevName, listLoad);
+ }
+ else
+ {
+ /* Plain disk partition. Trim the trailing digits to get the drive name */
+ getDiskName(szDevName, sizeof(szDevName), szFsName, true /*=fTrimDigits*/);
+ listUsage.push_back(RTCString(szDevName));
+ listLoad.push_back(RTCString(szDevName));
+ }
+ if (listUsage.empty() || listLoad.empty())
+ {
+ LogRel(("Failed to retrive disk info: getDiskName(%s) --> %s\n",
+ mntent->mnt_fsname, szDevName));
+ }
break;
}
}
diff --git a/src/VBox/Main/src-server/linux/USBGetDevices.cpp b/src/VBox/Main/src-server/linux/USBGetDevices.cpp
index d824a017..b4ef0df7 100644
--- a/src/VBox/Main/src-server/linux/USBGetDevices.cpp
+++ b/src/VBox/Main/src-server/linux/USBGetDevices.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -357,11 +357,11 @@ static int usbReadSpeed(const char *pszValue, USBDEVICESPEED *pSpd, char **ppszN
{
pszValue = RTStrStripL(pszValue);
/* verified with Linux 2.4.0 ... Linux 2.6.25 */
- if (!strncmp(pszValue, "1.5", 3))
+ if (!strncmp(pszValue, RT_STR_TUPLE("1.5")))
*pSpd = USBDEVICESPEED_LOW;
- else if (!strncmp(pszValue, "12 ", 3))
+ else if (!strncmp(pszValue, RT_STR_TUPLE("12 ")))
*pSpd = USBDEVICESPEED_FULL;
- else if (!strncmp(pszValue, "480", 3))
+ else if (!strncmp(pszValue, RT_STR_TUPLE("480")))
*pSpd = USBDEVICESPEED_HIGH;
else
*pSpd = USBDEVICESPEED_UNKNOWN;
@@ -593,7 +593,7 @@ static PUSBDEVICE getDevicesFromUsbfs(const char *pcszUsbfsRoot, bool testfs)
deviceFreeMembers(&Dev);
/* Reset device state */
- memset(&Dev, 0, sizeof (Dev));
+ RT_ZERO(Dev);
Dev.enmState = USBDEVICESTATE_UNUSED;
cHits = 1;
@@ -1122,7 +1122,7 @@ static int usbGetPortFromSysfsPath(const char *pszPath, uint8_t *pu8Port)
if (!pchDash && !pchDot)
{
/* No -/. so it must be a root hub. Check that it's usb<something>. */
- if (strncmp(pszLastComp, "usb", sizeof("usb") - 1) != 0)
+ if (strncmp(pszLastComp, RT_STR_TUPLE("usb")) != 0)
{
Log(("usbGetPortFromSysfsPath(%s): failed [2]\n", pszPath));
return VERR_INVALID_PARAMETER;
@@ -1430,7 +1430,7 @@ void TestUSBSetInotifyAvailable(bool fHaveInotifyLibC, bool fHaveInotifyKernel)
s_fHaveInotifyKernel = fHaveInotifyKernel;
}
# define dlsym testDLSym
-# define close(a) do {} while(0)
+# define close(a) do {} while (0)
#endif
/** Is inotify available and working on this system? This is a requirement
@@ -1586,7 +1586,7 @@ void TestUSBSetEnv(const char *pcszEnvUsb, const char *pcszEnvUsbRoot)
* what is available on the host and what if anything the user has specified
* in the environment.
* @returns iprt status value
- * @param pfUsingUsbfsDevices on success this will be set to true if
+ * @param pfUsingUsbfsDevices on success this will be set to true if
* the prefered access method is USBFS-like and to
* false if it is sysfs/device node-like
* @param ppcszDevicesRoot on success the root of the tree of USBFS-like
diff --git a/src/VBox/Main/src-server/linux/USBProxyServiceLinux.cpp b/src/VBox/Main/src-server/linux/USBProxyServiceLinux.cpp
index a89c3e00..82c97aa9 100644
--- a/src/VBox/Main/src-server/linux/USBProxyServiceLinux.cpp
+++ b/src/VBox/Main/src-server/linux/USBProxyServiceLinux.cpp
@@ -320,7 +320,7 @@ int USBProxyServiceLinux::waitUsbfs(RTMSINTERVAL aMillies)
aMillies = 500;
}
- memset(&PollFds, 0, sizeof(PollFds));
+ RT_ZERO(PollFds);
PollFds[0].fd = RTFileToNative(mhFile);
PollFds[0].events = POLLIN;
PollFds[1].fd = RTPipeToNative(mhWakeupPipeR);
diff --git a/src/VBox/Main/src-server/linux/vbox-libhal.cpp b/src/VBox/Main/src-server/linux/vbox-libhal.cpp
index 2e7c2716..ade8f072 100644
--- a/src/VBox/Main/src-server/linux/vbox-libhal.cpp
+++ b/src/VBox/Main/src-server/linux/vbox-libhal.cpp
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Main/src-server/os2/NetIf-os2.cpp b/src/VBox/Main/src-server/os2/NetIf-os2.cpp
index d0c287b5..cac174a7 100644
--- a/src/VBox/Main/src-server/os2/NetIf-os2.cpp
+++ b/src/VBox/Main/src-server/os2/NetIf-os2.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -33,23 +33,24 @@ int NetIfList(std::list <ComObjPtr<HostNetworkInterface> > &list)
return VERR_NOT_IMPLEMENTED;
}
-int NetIfEnableStaticIpConfig(VirtualBox *pVbox, HostNetworkInterface * pIf, ULONG ip, ULONG mask)
+int NetIfEnableStaticIpConfig(VirtualBox *pVBox, HostNetworkInterface * pIf, ULONG ip, ULONG mask)
{
return VERR_NOT_IMPLEMENTED;
}
-int NetIfEnableStaticIpConfigV6(VirtualBox *pVbox, HostNetworkInterface * pIf, IN_BSTR aIPV6Address, ULONG aIPV6MaskPrefixLength)
+int NetIfEnableStaticIpConfigV6(VirtualBox *pVBox, HostNetworkInterface * pIf, IN_BSTR aIPV6Address, ULONG aIPV6MaskPrefixLength)
{
return VERR_NOT_IMPLEMENTED;
}
-int NetIfEnableDynamicIpConfig(VirtualBox *pVbox, HostNetworkInterface * pIf)
+int NetIfEnableDynamicIpConfig(VirtualBox *pVBox, HostNetworkInterface * pIf)
{
return VERR_NOT_IMPLEMENTED;
}
-int NetIfDhcpRediscover(VirtualBox *pVbox, HostNetworkInterface * pIf)
+int NetIfDhcpRediscover(VirtualBox *pVBox, HostNetworkInterface * pIf)
{
return VERR_NOT_IMPLEMENTED;
}
+
diff --git a/src/VBox/Main/src-server/os2/PerformanceOs2.cpp b/src/VBox/Main/src-server/os2/PerformanceOs2.cpp
index e004ab83..054932ff 100644
--- a/src/VBox/Main/src-server/os2/PerformanceOs2.cpp
+++ b/src/VBox/Main/src-server/os2/PerformanceOs2.cpp
@@ -6,7 +6,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -39,31 +39,26 @@ CollectorHAL *createHAL()
int CollectorOS2::getHostCpuLoad(ULONG *user, ULONG *kernel, ULONG *idle)
{
- return E_NOTIMPL;
+ return VERR_NOT_IMPLEMENTED;
}
int CollectorOS2::getHostCpuMHz(ULONG *mhz)
{
- return E_NOTIMPL;
+ return VERR_NOT_IMPLEMENTED;
}
int CollectorOS2::getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available)
{
- return E_NOTIMPL;
+ return VERR_NOT_IMPLEMENTED;
}
int CollectorOS2::getProcessCpuLoad(RTPROCESS process, ULONG *user, ULONG *kernel)
{
- return E_NOTIMPL;
+ return VERR_NOT_IMPLEMENTED;
}
int CollectorOS2::getProcessMemoryUsage(RTPROCESS process, ULONG *used)
{
- return E_NOTIMPL;
-}
-
-int getDiskListByFs(const char *name, DiskList& list)
-{
return VERR_NOT_IMPLEMENTED;
}
diff --git a/src/VBox/Main/src-server/solaris/DynLoadLibSolaris.cpp b/src/VBox/Main/src-server/solaris/DynLoadLibSolaris.cpp
index 4bd864f1..a38b7654 100644
--- a/src/VBox/Main/src-server/solaris/DynLoadLibSolaris.cpp
+++ b/src/VBox/Main/src-server/solaris/DynLoadLibSolaris.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Main/src-server/solaris/DynLoadLibSolaris.h b/src/VBox/Main/src-server/solaris/DynLoadLibSolaris.h
index 4fc35b8a..e306dac0 100644
--- a/src/VBox/Main/src-server/solaris/DynLoadLibSolaris.h
+++ b/src/VBox/Main/src-server/solaris/DynLoadLibSolaris.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Main/src-server/solaris/NetIf-solaris.cpp b/src/VBox/Main/src-server/solaris/NetIf-solaris.cpp
index bc700820..82e8a338 100644
--- a/src/VBox/Main/src-server/solaris/NetIf-solaris.cpp
+++ b/src/VBox/Main/src-server/solaris/NetIf-solaris.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008-2011 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -24,6 +24,7 @@
#include <iprt/err.h>
#include <iprt/ctype.h>
+#include <iprt/mem.h>
#include <iprt/path.h>
#include <list>
@@ -73,10 +74,10 @@ static uint32_t getInstance(const char *pszIfaceName, char *pszDevName)
return uInstance;
}
-static uint64_t kstatGet(const char *name)
+static uint32_t kstatGet(const char *name)
{
kstat_ctl_t *kc;
- uint64_t uSpeed = 0;
+ uint32_t uSpeed = 0;
if ((kc = kstat_open()) == 0)
{
@@ -84,14 +85,14 @@ static uint64_t kstatGet(const char *name)
return 0;
}
- kstat_t *ksAdapter = kstat_lookup(kc, "link", -1, (char *)name);
+ kstat_t *ksAdapter = kstat_lookup(kc, (char *)"link", -1, (char *)name);
if (ksAdapter == 0)
{
char szModule[KSTAT_STRLEN];
uint32_t uInstance = getInstance(name, szModule);
- ksAdapter = kstat_lookup(kc, szModule, uInstance, "phys");
+ ksAdapter = kstat_lookup(kc, szModule, uInstance, (char *)"phys");
if (ksAdapter == 0)
- ksAdapter = kstat_lookup(kc, szModule, uInstance, name);
+ ksAdapter = kstat_lookup(kc, szModule, uInstance, (char*)name);
}
if (ksAdapter == 0)
LogRel(("Failed to get network statistics for %s\n", name));
@@ -103,15 +104,21 @@ static uint64_t kstatGet(const char *name)
if ((kn = (kstat_named_t *)kstat_data_lookup(ksAdapter, (char *)"ifspeed")) == 0)
LogRel(("kstat_data_lookup(ifspeed) -> %d, name=%s\n", errno, name));
else
- uSpeed = kn->value.ul;
+ uSpeed = kn->value.ul / 1000000; /* bits -> Mbits */
}
kstat_close(kc);
+ LogFlow(("kstatGet(%s) -> %u Mbit/s\n", name, uSpeed));
return uSpeed;
}
static void queryIfaceSpeed(PNETIFINFO pInfo)
{
- pInfo->uSpeedMbits = kstatGet(pInfo->szShortName) / 1000000; /* bits -> Mbits */
+ /* Don't query interface speed for inactive interfaces (see @bugref{6345}). */
+ if (pInfo->enmStatus == NETIF_S_UP)
+ pInfo->uSpeedMbits = kstatGet(pInfo->szShortName);
+ else
+ pInfo->uSpeedMbits = 0;
+ LogFlow(("queryIfaceSpeed(%s) -> %u\n", pInfo->szShortName, pInfo->uSpeedMbits));
}
static void vboxSolarisAddHostIface(char *pszIface, int Instance, void *pvHostNetworkInterfaceList)
@@ -192,12 +199,12 @@ static void vboxSolarisAddHostIface(char *pszIface, int Instance, void *pvHostNe
* Try to get IP V4 address and netmask as well as Ethernet address.
*/
NETIFINFO Info;
- memset(&Info, 0, sizeof(Info));
+ RT_ZERO(Info);
int Sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
if (Sock > 0)
{
struct lifreq IfReq;
- strcpy(IfReq.lifr_name, szNICInstance);
+ RTStrCopy(IfReq.lifr_name, sizeof(IfReq.lifr_name), szNICInstance);
if (ioctl(Sock, SIOCGLIFADDR, &IfReq) >= 0)
{
memcpy(Info.IPAddress.au8, &((struct sockaddr_in *)&IfReq.lifr_addr)->sin_addr.s_addr,
@@ -236,7 +243,7 @@ static void vboxSolarisAddHostIface(char *pszIface, int Instance, void *pvHostNe
if (Sock > 0)
{
struct lifreq IfReq;
- strcpy(IfReq.lifr_name, szNICInstance);
+ RTStrCopy(IfReq.lifr_name, sizeof(IfReq.lifr_name), szNICInstance);
if (ioctl(Sock, SIOCGLIFADDR, &IfReq) >= 0)
{
memcpy(Info.IPv6Address.au8, ((struct sockaddr_in6 *)&IfReq.lifr_addr)->sin6_addr.s6_addr,
@@ -269,7 +276,7 @@ static void vboxSolarisAddHostIface(char *pszIface, int Instance, void *pvHostNe
strncpy(Info.szShortName, szNICInstance, sizeof(Info.szShortName) - 1);
HostNetworkInterfaceType_T enmType;
- if (strncmp("vboxnet", szNICInstance, 7))
+ if (strncmp(szNICInstance, RT_STR_TUPLE("vboxnet")))
enmType = HostNetworkInterfaceType_Bridged;
else
enmType = HostNetworkInterfaceType_HostOnly;
@@ -285,15 +292,15 @@ static boolean_t vboxSolarisAddLinkHostIface(const char *pszIface, void *pvHostN
/*
* Skip IPSEC interfaces. It's at IP level.
*/
- if (!strncmp(pszIface, "ip.tun", 6))
+ if (!strncmp(pszIface, RT_STR_TUPLE("ip.tun")))
return _B_FALSE;
/*
* Skip our own dynamic VNICs but don't skip VNIC templates.
* These names originate from VBoxNetFltBow-solaris.c, hardcoded here for now.
*/
- if ( strncmp(pszIface, "vboxvnic_template", 17)
- && !strncmp(pszIface, "vboxvnic", 8))
+ if ( strncmp(pszIface, RT_STR_TUPLE("vboxvnic_template"))
+ && !strncmp(pszIface, RT_STR_TUPLE("vboxvnic")))
return _B_FALSE;
/*
@@ -406,59 +413,65 @@ int NetIfList(std::list <ComObjPtr<HostNetworkInterface> > &list)
if (Sock > 0)
{
struct lifnum IfNum;
- memset(&IfNum, 0, sizeof(IfNum));
+ RT_ZERO(IfNum);
IfNum.lifn_family = AF_INET;
int rc = ioctl(Sock, SIOCGLIFNUM, &IfNum);
if (!rc)
{
- struct lifreq Ifaces[24];
- struct lifconf IfConfig;
- memset(&IfConfig, 0, sizeof(IfConfig));
- IfConfig.lifc_family = AF_INET;
- IfConfig.lifc_len = sizeof(Ifaces);
- IfConfig.lifc_buf = (caddr_t)&(Ifaces[0]);
- rc = ioctl(Sock, SIOCGLIFCONF, &IfConfig);
- if (!rc)
+ int cIfaces = RT_MIN(1024, IfNum.lifn_count); /* sane limit */
+ int cbIfaces = cIfaces * sizeof(struct lifreq);
+ struct lifreq *Ifaces = (struct lifreq *)RTMemTmpAlloc(cbIfaces);
+ if (Ifaces)
{
- for (int i = 0; i < IfNum.lifn_count; i++)
+ struct lifconf IfConfig;
+ RT_ZERO(IfConfig);
+ IfConfig.lifc_family = AF_INET;
+ IfConfig.lifc_len = cbIfaces;
+ IfConfig.lifc_buf = (caddr_t)Ifaces;
+ rc = ioctl(Sock, SIOCGLIFCONF, &IfConfig);
+ if (!rc)
{
- /*
- * Skip loopback interfaces.
- */
- if (!strncmp(Ifaces[i].lifr_name, "lo", 2))
- continue;
-
-#if 0
- rc = ioctl(Sock, SIOCGLIFADDR, &(Ifaces[i]));
- if (rc >= 0)
+ for (int i = 0; i < cIfaces; i++)
{
- memcpy(Info.IPAddress.au8, ((struct sockaddr *)&Ifaces[i].lifr_addr)->sa_data,
- sizeof(Info.IPAddress.au8));
- // SIOCGLIFNETMASK
- struct arpreq ArpReq;
- memcpy(&ArpReq.arp_pa, &Ifaces[i].lifr_addr, sizeof(struct sockaddr_in));
-
/*
- * We might fail if the interface has not been assigned an IP address.
- * That doesn't matter; as long as it's plumbed we can pick it up.
- * But, if it has not acquired an IP address we cannot obtain it's MAC
- * address this way, so we just use all zeros there.
+ * Skip loopback interfaces.
*/
- rc = ioctl(Sock, SIOCGARP, &ArpReq);
+ if (!strncmp(Ifaces[i].lifr_name, RT_STR_TUPLE("lo")))
+ continue;
+
+#if 0
+ rc = ioctl(Sock, SIOCGLIFADDR, &(Ifaces[i]));
if (rc >= 0)
- memcpy(&Info.MACAddress, ArpReq.arp_ha.sa_data, sizeof(Info.MACAddress));
+ {
+ memcpy(Info.IPAddress.au8, ((struct sockaddr *)&Ifaces[i].lifr_addr)->sa_data,
+ sizeof(Info.IPAddress.au8));
+ // SIOCGLIFNETMASK
+ struct arpreq ArpReq;
+ memcpy(&ArpReq.arp_pa, &Ifaces[i].lifr_addr, sizeof(struct sockaddr_in));
+
+ /*
+ * We might fail if the interface has not been assigned an IP address.
+ * That doesn't matter; as long as it's plumbed we can pick it up.
+ * But, if it has not acquired an IP address we cannot obtain it's MAC
+ * address this way, so we just use all zeros there.
+ */
+ rc = ioctl(Sock, SIOCGARP, &ArpReq);
+ if (rc >= 0)
+ memcpy(&Info.MACAddress, ArpReq.arp_ha.sa_data, sizeof(Info.MACAddress));
+
+ char szNICDesc[LIFNAMSIZ + 256];
+ char *pszIface = Ifaces[i].lifr_name;
+ strcpy(szNICDesc, pszIface);
+
+ vboxSolarisAddLinkHostIface(pszIface, &list);
+ }
+#endif
- char szNICDesc[LIFNAMSIZ + 256];
char *pszIface = Ifaces[i].lifr_name;
- strcpy(szNICDesc, pszIface);
-
vboxSolarisAddLinkHostIface(pszIface, &list);
}
-#endif
-
- char *pszIface = Ifaces[i].lifr_name;
- vboxSolarisAddLinkHostIface(pszIface, &list);
}
+ RTMemTmpFree(Ifaces);
}
}
close(Sock);
@@ -486,3 +499,17 @@ int NetIfGetConfigByName(PNETIFINFO pInfo)
return VERR_NOT_IMPLEMENTED;
}
+/**
+ * Retrieve the physical link speed in megabits per second. If the interface is
+ * not up or otherwise unavailable the zero speed is returned.
+ *
+ * @returns VBox status code.
+ *
+ * @param pcszIfName Interface name.
+ * @param puMbits Where to store the link speed.
+ */
+int NetIfGetLinkSpeed(const char *pcszIfName, uint32_t *puMbits)
+{
+ *puMbits = kstatGet(pcszIfName);
+ return VINF_SUCCESS;
+}
diff --git a/src/VBox/Main/src-server/solaris/PerformanceSolaris.cpp b/src/VBox/Main/src-server/solaris/PerformanceSolaris.cpp
index 7abeae04..ed935116 100644
--- a/src/VBox/Main/src-server/solaris/PerformanceSolaris.cpp
+++ b/src/VBox/Main/src-server/solaris/PerformanceSolaris.cpp
@@ -6,7 +6,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -26,33 +26,85 @@
#include <unistd.h>
#include <sys/sysinfo.h>
#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/statvfs.h>
#include <iprt/ctype.h>
#include <iprt/err.h>
#include <iprt/string.h>
#include <iprt/alloc.h>
#include <iprt/param.h>
-#include <VBox/log.h>
+#include <iprt/path.h>
+#include <iprt/system.h>
+
+#include "Logging.h"
#include "Performance.h"
+#include <dlfcn.h>
+
+#include <libzfs.h>
+#include <libnvpair.h>
+
+#include <map>
+
namespace pm {
+ typedef libzfs_handle_t *(*PFNZFSINIT)(void);
+ typedef void (*PFNZFSFINI)(libzfs_handle_t *);
+ typedef zfs_handle_t *(*PFNZFSOPEN)(libzfs_handle_t *, const char *, int);
+ typedef void (*PFNZFSCLOSE)(zfs_handle_t *);
+ typedef uint64_t (*PFNZFSPROPGETINT)(zfs_handle_t *, zfs_prop_t);
+ typedef zpool_handle_t *(*PFNZPOOLOPEN)(libzfs_handle_t *, const char *);
+ typedef void (*PFNZPOOLCLOSE)(zpool_handle_t *);
+ typedef nvlist_t *(*PFNZPOOLGETCONFIG)(zpool_handle_t *, nvlist_t **);
+ typedef char *(*PFNZPOOLVDEVNAME)(libzfs_handle_t *, zpool_handle_t *, nvlist_t *, boolean_t);
+
+ typedef std::map<RTCString,RTCString> FsMap;
+
class CollectorSolaris : public CollectorHAL
{
public:
CollectorSolaris();
virtual ~CollectorSolaris();
virtual int getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available);
+ virtual int getHostFilesystemUsage(const char *name, ULONG *total, ULONG *used, ULONG *available);
+ virtual int getHostDiskSize(const char *name, uint64_t *size);
virtual int getProcessMemoryUsage(RTPROCESS process, ULONG *used);
virtual int getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle);
virtual int getRawHostNetworkLoad(const char *name, uint64_t *rx, uint64_t *tx);
+ virtual int getRawHostDiskLoad(const char *name, uint64_t *disk_ms, uint64_t *total_ms);
virtual int getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total);
+
+ virtual int getDiskListByFs(const char *name, DiskList& listUsage, DiskList& listLoad);
private:
static uint32_t getInstance(const char *pszIfaceName, char *pszDevName);
- kstat_ctl_t *mKC;
- kstat_t *mSysPages;
- kstat_t *mZFSCache;
+ uint64_t getZfsTotal(uint64_t cbTotal, const char *szFsType, const char *szFsName);
+ void updateFilesystemMap(void);
+ RTCString physToInstName(const char *pcszPhysName);
+ RTCString pathToInstName(const char *pcszDevPathName);
+ uint64_t wrapCorrection(uint32_t cur, uint64_t prev, const char *name);
+ uint64_t wrapDetection(uint64_t cur, uint64_t prev, const char *name);
+
+ kstat_ctl_t *mKC;
+ kstat_t *mSysPages;
+ kstat_t *mZFSCache;
+
+ void *mZfsSo;
+ libzfs_handle_t *mZfsLib;
+ PFNZFSINIT mZfsInit;
+ PFNZFSFINI mZfsFini;
+ PFNZFSOPEN mZfsOpen;
+ PFNZFSCLOSE mZfsClose;
+ PFNZFSPROPGETINT mZfsPropGetInt;
+ PFNZPOOLOPEN mZpoolOpen;
+ PFNZPOOLCLOSE mZpoolClose;
+ PFNZPOOLGETCONFIG mZpoolGetConfig;
+ PFNZPOOLVDEVNAME mZpoolVdevName;
+
+ FsMap mFsMap;
+ uint32_t mCpus;
+ ULONG totalRAM;
};
CollectorHAL *createHAL()
@@ -66,7 +118,9 @@ CollectorHAL *createHAL()
CollectorSolaris::CollectorSolaris()
: mKC(0),
mSysPages(0),
- mZFSCache(0)
+ mZFSCache(0),
+ mZfsLib(0),
+ mCpus(0)
{
if ((mKC = kstat_open()) == 0)
{
@@ -84,12 +138,55 @@ CollectorSolaris::CollectorSolaris()
{
Log(("kstat_lookup(system_pages) -> %d\n", errno));
}
+
+ /* Try to load libzfs dynamically, it may be missing. */
+ mZfsSo = dlopen("libzfs.so", RTLD_LAZY);
+ if (mZfsSo)
+ {
+ mZfsInit = (PFNZFSINIT)(uintptr_t)dlsym(mZfsSo, "libzfs_init");
+ mZfsFini = (PFNZFSFINI)(uintptr_t)dlsym(mZfsSo, "libzfs_fini");
+ mZfsOpen = (PFNZFSOPEN)(uintptr_t)dlsym(mZfsSo, "zfs_open");
+ mZfsClose = (PFNZFSCLOSE)(uintptr_t)dlsym(mZfsSo, "zfs_close");
+ mZfsPropGetInt = (PFNZFSPROPGETINT)(uintptr_t)dlsym(mZfsSo, "zfs_prop_get_int");
+ mZpoolOpen = (PFNZPOOLOPEN)(uintptr_t)dlsym(mZfsSo, "zpool_open");
+ mZpoolClose = (PFNZPOOLCLOSE)(uintptr_t)dlsym(mZfsSo, "zpool_close");
+ mZpoolGetConfig = (PFNZPOOLGETCONFIG)(uintptr_t)dlsym(mZfsSo, "zpool_get_config");
+ mZpoolVdevName = (PFNZPOOLVDEVNAME)(uintptr_t)dlsym(mZfsSo, "zpool_vdev_name");
+
+ if ( mZfsInit
+ && mZfsOpen
+ && mZfsClose
+ && mZfsPropGetInt
+ && mZpoolOpen
+ && mZpoolClose
+ && mZpoolGetConfig
+ && mZpoolVdevName)
+ mZfsLib = mZfsInit();
+ else
+ LogRel(("Incompatible libzfs? libzfs_init=%p zfs_open=%p zfs_close=%p zfs_prop_get_int=%p\n",
+ mZfsInit, mZfsOpen, mZfsClose, mZfsPropGetInt));
+ }
+
+ updateFilesystemMap();
+ /* Notice that mCpus member will be initialized by HostCpuLoadRaw::init() */
+
+ uint64_t cb;
+ int rc = RTSystemQueryTotalRam(&cb);
+ if (RT_FAILURE(rc))
+ totalRAM = 0;
+ else
+ totalRAM = (ULONG)(cb / 1024);
}
CollectorSolaris::~CollectorSolaris()
{
if (mKC)
kstat_close(mKC);
+ /* Not calling libzfs_fini() causes file descriptor leaks (#6788). */
+ if (mZfsFini && mZfsLib)
+ mZfsFini(mZfsLib);
+ if (mZfsSo)
+ dlclose(mZfsSo);
}
int CollectorSolaris::getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle)
@@ -123,6 +220,8 @@ int CollectorSolaris::getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64
Log(("no cpu stats found!\n"));
return VERR_INTERNAL_ERROR;
}
+ else
+ mCpus = cpus;
if (user) *user = tmpUser;
if (kernel) *kernel = tmpKernel;
@@ -148,8 +247,18 @@ int CollectorSolaris::getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, ui
{
//Assert((pid_t)process == pstatus.pr_pid);
//Log(("user=%u kernel=%u total=%u\n", prusage.pr_utime.tv_sec, prusage.pr_stime.tv_sec, prusage.pr_tstamp.tv_sec));
- *user = (uint64_t)prusage.pr_utime.tv_sec * 1000000000 + prusage.pr_utime.tv_nsec;
- *kernel = (uint64_t)prusage.pr_stime.tv_sec * 1000000000 + prusage.pr_stime.tv_nsec;
+ /*
+ * The CPU time spent must be adjusted by the number of cores for compatibility with
+ * other platforms (see @bugref{6345}).
+ */
+ Assert(mCpus);
+ if (mCpus)
+ {
+ *user = ((uint64_t)prusage.pr_utime.tv_sec * 1000000000 + prusage.pr_utime.tv_nsec) / mCpus;
+ *kernel = ((uint64_t)prusage.pr_stime.tv_sec * 1000000000 + prusage.pr_stime.tv_nsec) / mCpus;
+ }
+ else
+ *user = *kernel = 0;
*total = (uint64_t)prusage.pr_tstamp.tv_sec * 1000000000 + prusage.pr_tstamp.tv_nsec;
//Log(("user=%llu kernel=%llu total=%llu\n", *user, *kernel, *total));
}
@@ -171,61 +280,15 @@ int CollectorSolaris::getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, ui
int CollectorSolaris::getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available)
{
- int rc = VINF_SUCCESS;
-
- kstat_named_t *kn;
-
- if (mKC == 0 || mSysPages == 0)
- return VERR_INTERNAL_ERROR;
-
- if (kstat_read(mKC, mSysPages, 0) == -1)
+ AssertReturn(totalRAM, VERR_INTERNAL_ERROR);
+ uint64_t cb;
+ int rc = RTSystemQueryAvailableRam(&cb);
+ if (RT_SUCCESS(rc))
{
- Log(("kstat_read(sys_pages) -> %d\n", errno));
- return VERR_INTERNAL_ERROR;
+ *total = totalRAM;
+ *available = cb / 1024;
+ *used = *total - *available;
}
- if ((kn = (kstat_named_t *)kstat_data_lookup(mSysPages, (char *)"freemem")) == 0)
- {
- Log(("kstat_data_lookup(freemem) -> %d\n", errno));
- return VERR_INTERNAL_ERROR;
- }
- *available = kn->value.ul * (PAGE_SIZE/1024);
-
- if (kstat_read(mKC, mZFSCache, 0) != -1)
- {
- if (mZFSCache)
- {
- if ((kn = (kstat_named_t *)kstat_data_lookup(mZFSCache, (char *)"size")))
- {
- ulong_t ulSize = kn->value.ul;
-
- if ((kn = (kstat_named_t *)kstat_data_lookup(mZFSCache, (char *)"c_min")))
- {
- /*
- * Account for ZFS minimum arc cache size limit.
- * "c_min" is the target minimum size of the ZFS cache, and not the hard limit. It's possible
- * for "size" to shrink below "c_min" (e.g: during boot & high memory consumption).
- */
- ulong_t ulMin = kn->value.ul;
- *available += ulSize > ulMin ? (ulSize - ulMin) / 1024 : 0;
- }
- else
- Log(("kstat_data_lookup(c_min) ->%d\n", errno));
- }
- else
- Log(("kstat_data_lookup(size) -> %d\n", errno));
- }
- else
- Log(("mZFSCache missing.\n"));
- }
-
- if ((kn = (kstat_named_t *)kstat_data_lookup(mSysPages, (char *)"physmem")) == 0)
- {
- Log(("kstat_data_lookup(physmem) -> %d\n", errno));
- return VERR_INTERNAL_ERROR;
- }
- *total = kn->value.ul * (PAGE_SIZE/1024);
- *used = *total - *available;
-
return rc;
}
@@ -285,21 +348,53 @@ uint32_t CollectorSolaris::getInstance(const char *pszIfaceName, char *pszDevNam
return uInstance;
}
+uint64_t CollectorSolaris::wrapCorrection(uint32_t cur, uint64_t prev, const char *name)
+{
+ NOREF(name);
+ uint64_t corrected = (prev & 0xffffffff00000000) + cur;
+ if (cur < (prev & 0xffffffff))
+ {
+ /* wrap has occurred */
+ corrected += 0x100000000;
+ LogFlowThisFunc(("Corrected wrap on %s (%u < %u), returned %llu.\n",
+ name, cur, (uint32_t)prev, corrected));
+ }
+ return corrected;
+}
+
+uint64_t CollectorSolaris::wrapDetection(uint64_t cur, uint64_t prev, const char *name)
+{
+ static bool fNotSeen = true;
+
+ if (fNotSeen && cur < prev)
+ {
+ fNotSeen = false;
+ LogRel(("Detected wrap on %s (%llu < %llu).\n", name, cur, prev));
+ }
+ return cur;
+}
+
+/*
+ * WARNING! This function expects the previous values of rx and tx counter to
+ * be passed in as well as returnes new values in the same parameters. This is
+ * needed to provide a workaround for 32-bit counter wrapping.
+ */
int CollectorSolaris::getRawHostNetworkLoad(const char *name, uint64_t *rx, uint64_t *tx)
{
+ static bool g_fNotReported = true;
AssertReturn(strlen(name) < KSTAT_STRLEN, VERR_INVALID_PARAMETER);
LogFlowThisFunc(("m=%s i=%d n=%s\n", "link", -1, name));
- kstat_t *ksAdapter = kstat_lookup(mKC, "link", -1, (char *)name);
+ kstat_t *ksAdapter = kstat_lookup(mKC, (char *)"link", -1, (char *)name);
if (ksAdapter == 0)
{
char szModule[KSTAT_STRLEN];
uint32_t uInstance = getInstance(name, szModule);
LogFlowThisFunc(("m=%s i=%u n=%s\n", szModule, uInstance, "phys"));
- ksAdapter = kstat_lookup(mKC, szModule, uInstance, "phys");
+ ksAdapter = kstat_lookup(mKC, szModule, uInstance, (char *)"phys");
if (ksAdapter == 0)
{
LogFlowThisFunc(("m=%s i=%u n=%s\n", szModule, uInstance, name));
- ksAdapter = kstat_lookup(mKC, szModule, uInstance, name);
+ ksAdapter = kstat_lookup(mKC, szModule, uInstance, (char *)name);
if (ksAdapter == 0)
{
LogRel(("Failed to get network statistics for %s\n", name));
@@ -313,24 +408,311 @@ int CollectorSolaris::getRawHostNetworkLoad(const char *name, uint64_t *rx, uint
return VERR_INTERNAL_ERROR;
}
kstat_named_t *kn;
- if ((kn = (kstat_named_t *)kstat_data_lookup(ksAdapter, (char *)"rbytes")) == 0)
+ if ((kn = (kstat_named_t *)kstat_data_lookup(ksAdapter, (char *)"rbytes64")) == 0)
{
- LogRel(("kstat_data_lookup(rbytes) -> %d, name=%s\n", errno, name));
- return VERR_INTERNAL_ERROR;
+ if (g_fNotReported)
+ {
+ g_fNotReported = false;
+ LogRel(("Failed to locate rbytes64, falling back to 32-bit counters...\n"));
+ }
+ if ((kn = (kstat_named_t *)kstat_data_lookup(ksAdapter, (char *)"rbytes")) == 0)
+ {
+ LogRel(("kstat_data_lookup(rbytes) -> %d, name=%s\n", errno, name));
+ return VERR_INTERNAL_ERROR;
+ }
+ *rx = wrapCorrection(kn->value.ul, *rx, "rbytes");
}
- *rx = kn->value.ul;
- if ((kn = (kstat_named_t *)kstat_data_lookup(ksAdapter, (char *)"obytes")) == 0)
+ else
+ *rx = wrapDetection(kn->value.ull, *rx, "rbytes64");
+ if ((kn = (kstat_named_t *)kstat_data_lookup(ksAdapter, (char *)"obytes64")) == 0)
{
- LogRel(("kstat_data_lookup(obytes) -> %d\n", errno));
- return VERR_INTERNAL_ERROR;
+ if (g_fNotReported)
+ {
+ g_fNotReported = false;
+ LogRel(("Failed to locate obytes64, falling back to 32-bit counters...\n"));
+ }
+ if ((kn = (kstat_named_t *)kstat_data_lookup(ksAdapter, (char *)"obytes")) == 0)
+ {
+ LogRel(("kstat_data_lookup(obytes) -> %d\n", errno));
+ return VERR_INTERNAL_ERROR;
+ }
+ *tx = wrapCorrection(kn->value.ul, *tx, "obytes");
+ }
+ else
+ *tx = wrapDetection(kn->value.ull, *tx, "obytes64");
+ return VINF_SUCCESS;
+}
+
+int CollectorSolaris::getRawHostDiskLoad(const char *name, uint64_t *disk_ms, uint64_t *total_ms)
+{
+ int rc = VINF_SUCCESS;
+ AssertReturn(strlen(name) < KSTAT_STRLEN, VERR_INVALID_PARAMETER);
+ LogFlowThisFunc(("n=%s\n", name));
+ kstat_t *ksDisk = kstat_lookup(mKC, NULL, -1, (char *)name);
+ if (ksDisk != 0)
+ {
+ if (kstat_read(mKC, ksDisk, 0) == -1)
+ {
+ LogRel(("kstat_read(%s) -> %d\n", name, errno));
+ rc = VERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ kstat_io_t *ksIo = KSTAT_IO_PTR(ksDisk);
+ /*
+ * We do not care for wrap possibility here, although we may
+ * reconsider in about 300 years (9223372036854775807 ns).
+ */
+ *disk_ms = ksIo->rtime / 1000000;
+ *total_ms = ksDisk->ks_snaptime / 1000000;
+ }
}
- *tx = kn->value.ul;
+ else
+ {
+ LogRel(("kstat_lookup(%s) -> %d\n", name, errno));
+ rc = VERR_INTERNAL_ERROR;
+ }
+
+ return rc;
+}
+
+uint64_t CollectorSolaris::getZfsTotal(uint64_t cbTotal, const char *szFsType, const char *szFsName)
+{
+ if (strcmp(szFsType, "zfs"))
+ return cbTotal;
+ FsMap::iterator it = mFsMap.find(szFsName);
+ if (it == mFsMap.end())
+ return cbTotal;
+
+ char *pszDataset = strdup(it->second.c_str());
+ char *pszEnd = pszDataset + strlen(pszDataset);
+ uint64_t uAvail = 0;
+ while (pszEnd)
+ {
+ zfs_handle_t *hDataset;
+
+ *pszEnd = 0;
+ hDataset = mZfsOpen(mZfsLib, pszDataset, ZFS_TYPE_DATASET);
+ if (!hDataset)
+ break;
+
+ if (uAvail == 0)
+ {
+ uAvail = mZfsPropGetInt(hDataset, ZFS_PROP_REFQUOTA);
+ if (uAvail == 0)
+ uAvail = UINT64_MAX;
+ }
+
+ uint64_t uQuota = mZfsPropGetInt(hDataset, ZFS_PROP_QUOTA);
+ if (uQuota && uAvail > uQuota)
+ uAvail = uQuota;
+
+ pszEnd = strrchr(pszDataset, '/');
+ if (!pszEnd)
+ {
+ uint64_t uPoolSize = mZfsPropGetInt(hDataset, ZFS_PROP_USED) +
+ mZfsPropGetInt(hDataset, ZFS_PROP_AVAILABLE);
+ if (uAvail > uPoolSize)
+ uAvail = uPoolSize;
+ }
+ mZfsClose(hDataset);
+ }
+ free(pszDataset);
+
+ return uAvail ? uAvail : cbTotal;
+}
+
+int CollectorSolaris::getHostFilesystemUsage(const char *path, ULONG *total, ULONG *used, ULONG *available)
+{
+ struct statvfs64 stats;
+
+ if (statvfs64(path, &stats) == -1)
+ {
+ LogRel(("Failed to collect %s filesystem usage: errno=%d.\n", path, errno));
+ return VERR_ACCESS_DENIED;
+ }
+ uint64_t cbBlock = stats.f_frsize ? stats.f_frsize : stats.f_bsize;
+ *total = (ULONG)(getZfsTotal(cbBlock * stats.f_blocks, stats.f_basetype, path) / _1M);
+ LogFlowThisFunc(("f_blocks=%llu.\n", stats.f_blocks));
+ *used = (ULONG)(cbBlock * (stats.f_blocks - stats.f_bfree) / _1M);
+ *available = (ULONG)(cbBlock * stats.f_bavail / _1M);
+
return VINF_SUCCESS;
}
-int getDiskListByFs(const char *name, DiskList& list)
+int CollectorSolaris::getHostDiskSize(const char *name, uint64_t *size)
{
- return VERR_NOT_IMPLEMENTED;
+ int rc = VINF_SUCCESS;
+ AssertReturn(strlen(name) + 5 < KSTAT_STRLEN, VERR_INVALID_PARAMETER);
+ LogFlowThisFunc(("n=%s\n", name));
+ char szName[KSTAT_STRLEN];
+ strcpy(szName, name);
+ strcat(szName, ",err");
+ kstat_t *ksDisk = kstat_lookup(mKC, NULL, -1, szName);
+ if (ksDisk != 0)
+ {
+ if (kstat_read(mKC, ksDisk, 0) == -1)
+ {
+ LogRel(("kstat_read(%s) -> %d\n", name, errno));
+ rc = VERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ kstat_named_t *kn;
+ if ((kn = (kstat_named_t *)kstat_data_lookup(ksDisk, (char *)"Size")) == 0)
+ {
+ LogRel(("kstat_data_lookup(rbytes) -> %d, name=%s\n", errno, name));
+ return VERR_INTERNAL_ERROR;
+ }
+ *size = kn->value.ull;
+ }
+ }
+ else
+ {
+ LogRel(("kstat_lookup(%s) -> %d\n", szName, errno));
+ rc = VERR_INTERNAL_ERROR;
+ }
+
+
+ return rc;
+}
+
+RTCString CollectorSolaris::physToInstName(const char *pcszPhysName)
+{
+ FILE *fp = fopen("/etc/path_to_inst", "r");
+ if (!fp)
+ return RTCString();
+
+ RTCString strInstName;
+ size_t cbName = strlen(pcszPhysName);
+ char szBuf[RTPATH_MAX];
+ while (fgets(szBuf, sizeof(szBuf), fp))
+ {
+ if (szBuf[0] == '"' && strncmp(szBuf + 1, pcszPhysName, cbName) == 0)
+ {
+ char *pszDriver, *pszInstance;
+ pszDriver = strrchr(szBuf, '"');
+ if (pszDriver)
+ {
+ *pszDriver = '\0';
+ pszDriver = strrchr(szBuf, '"');
+ if (pszDriver)
+ {
+ *pszDriver++ = '\0';
+ pszInstance = strrchr(szBuf, ' ');
+ if (pszInstance)
+ {
+ *pszInstance = '\0';
+ pszInstance = strrchr(szBuf, ' ');
+ if (pszInstance)
+ {
+ *pszInstance++ = '\0';
+ strInstName = pszDriver;
+ strInstName += pszInstance;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ fclose(fp);
+
+ return strInstName;
+}
+
+RTCString CollectorSolaris::pathToInstName(const char *pcszDevPathName)
+{
+ char szLink[RTPATH_MAX];
+ if (readlink(pcszDevPathName, szLink, sizeof(szLink)) != -1)
+ {
+ char *pszStart, *pszEnd;
+ pszStart = strstr(szLink, "/devices/");
+ pszEnd = strrchr(szLink, ':');
+ if (pszStart && pszEnd)
+ {
+ pszStart += 8; // Skip "/devices"
+ *pszEnd = '\0'; // Trim partition
+ return physToInstName(pszStart);
+ }
+ }
+
+ return RTCString(pcszDevPathName);
+}
+
+int CollectorSolaris::getDiskListByFs(const char *name, DiskList& listUsage, DiskList& listLoad)
+{
+ FsMap::iterator it = mFsMap.find(name);
+ if (it == mFsMap.end())
+ return VERR_INVALID_PARAMETER;
+
+ RTCString strName = it->second.substr(0, it->second.find("/"));
+ if (mZpoolOpen && mZpoolClose && mZpoolGetConfig && !strName.isEmpty())
+ {
+ zpool_handle_t *zh = mZpoolOpen(mZfsLib, strName.c_str());
+ if (zh)
+ {
+ unsigned int cChildren = 0;
+ nvlist_t **nvChildren = NULL;
+ nvlist_t *nvRoot = NULL;
+ nvlist_t *nvConfig = mZpoolGetConfig(zh, NULL);
+ if ( !nvlist_lookup_nvlist(nvConfig, ZPOOL_CONFIG_VDEV_TREE, &nvRoot)
+ && !nvlist_lookup_nvlist_array(nvRoot, ZPOOL_CONFIG_CHILDREN, &nvChildren, &cChildren))
+ {
+ for (unsigned int i = 0; i < cChildren; ++i)
+ {
+ uint64_t fHole = 0;
+ uint64_t fLog = 0;
+
+ nvlist_lookup_uint64(nvChildren[i], ZPOOL_CONFIG_IS_HOLE, &fHole);
+ nvlist_lookup_uint64(nvChildren[i], ZPOOL_CONFIG_IS_LOG, &fLog);
+
+ if (!fHole && !fLog)
+ {
+ char *pszChildName = mZpoolVdevName(mZfsLib, zh, nvChildren[i], _B_FALSE);
+ Assert(pszChildName);
+ RTCString strDevPath("/dev/dsk/");
+ strDevPath += pszChildName;
+ char szLink[RTPATH_MAX];
+ if (readlink(strDevPath.c_str(), szLink, sizeof(szLink)) != -1)
+ {
+ char *pszStart, *pszEnd;
+ pszStart = strstr(szLink, "/devices/");
+ pszEnd = strrchr(szLink, ':');
+ if (pszStart && pszEnd)
+ {
+ pszStart += 8; // Skip "/devices"
+ *pszEnd = '\0'; // Trim partition
+ listUsage.push_back(physToInstName(pszStart));
+ }
+ }
+ free(pszChildName);
+ }
+ }
+ }
+ mZpoolClose(zh);
+ }
+ }
+ else
+ listUsage.push_back(pathToInstName(it->second.c_str()));
+ listLoad = listUsage;
+ return VINF_SUCCESS;
+}
+
+void CollectorSolaris::updateFilesystemMap(void)
+{
+ FILE *fp = fopen("/etc/mnttab", "r");
+ if (fp)
+ {
+ struct mnttab Entry;
+ int rc = 0;
+ resetmnttab(fp);
+ while ((rc = getmntent(fp, &Entry)) == 0)
+ mFsMap[Entry.mnt_mountp] = Entry.mnt_special;
+ fclose(fp);
+ if (rc != -1)
+ LogRel(("Error while reading mnttab: %d\n", rc));
+ }
}
}
diff --git a/src/VBox/Main/src-server/solaris/USBProxyServiceSolaris.cpp b/src/VBox/Main/src-server/solaris/USBProxyServiceSolaris.cpp
index 8261d990..0d6d85e8 100644
--- a/src/VBox/Main/src-server/solaris/USBProxyServiceSolaris.cpp
+++ b/src/VBox/Main/src-server/solaris/USBProxyServiceSolaris.cpp
@@ -173,7 +173,7 @@ static int solarisWalkDeviceNode(di_node_t Node, void *pvArg)
char *pszCompatNames = NULL;
int cCompatNames = di_compatible_names(Node, &pszCompatNames);
for (int i = 0; i < cCompatNames; i++, pszCompatNames += strlen(pszCompatNames) + 1)
- if (!strncmp(pszCompatNames, "usb", 3))
+ if (!strncmp(pszCompatNames, RT_STR_TUPLE("usb")))
{
fUSBDevice = true;
break;
@@ -304,7 +304,7 @@ static int solarisWalkDeviceNode(di_node_t Node, void *pvArg)
pList->pTail = pList->pHead = pCur;
rc = DI_WALK_CONTINUE;
- } while(0);
+ } while (0);
di_devfs_path_free(pszDevicePath);
if (!fValidDevice)
@@ -322,7 +322,7 @@ static USBDEVICESTATE solarisDetermineUSBDeviceState(PUSBDEVICE pDevice, di_node
if (!pszDriverName)
return USBDEVICESTATE_UNUSED;
- if (!strncmp(pszDriverName, VBOXUSB_DRIVER_NAME, sizeof(VBOXUSB_DRIVER_NAME) - 1))
+ if (!strncmp(pszDriverName, RT_STR_TUPLE(VBOXUSB_DRIVER_NAME)))
return USBDEVICESTATE_HELD_BY_PROXY;
NOREF(pDevice);
diff --git a/src/VBox/Main/src-server/win/HostDnsServiceWin.cpp b/src/VBox/Main/src-server/win/HostDnsServiceWin.cpp
new file mode 100644
index 00000000..1bd72233
--- /dev/null
+++ b/src/VBox/Main/src-server/win/HostDnsServiceWin.cpp
@@ -0,0 +1,233 @@
+/* -*- indent-tabs-mode: nil; -*- */
+#include <VBox/com/string.h>
+#include <VBox/com/ptr.h>
+
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+
+#include <Windows.h>
+
+#include <string>
+#include <vector>
+#include "../HostDnsService.h"
+
+struct HostDnsServiceWin::Data
+{
+ HostDnsServiceWin::Data(){}
+ HKEY hKeyTcpipParameters;
+#define DATA_DNS_UPDATE_EVENT 0
+#define DATA_SHUTDOWN_EVENT 1
+#define DATA_MAX_EVENT 2
+ HANDLE haDataEvent[DATA_MAX_EVENT];
+};
+
+static inline int registerNotification(const HKEY& hKey, HANDLE& hEvent)
+{
+ LONG lrc = RegNotifyChangeKeyValue(hKey,
+ TRUE,
+ REG_NOTIFY_CHANGE_LAST_SET,
+ hEvent,
+ TRUE);
+ AssertMsgReturn(lrc == ERROR_SUCCESS,
+ ("Failed to register event on the key. Please debug me!"),
+ VERR_INTERNAL_ERROR);
+
+ return VINF_SUCCESS;
+}
+
+HostDnsServiceWin::HostDnsServiceWin():HostDnsMonitor(true), m(NULL)
+{
+ m = new Data();
+
+ m->haDataEvent[DATA_DNS_UPDATE_EVENT] = CreateEvent(NULL,
+ TRUE, FALSE, NULL);
+ AssertReleaseMsg(m->haDataEvent[DATA_DNS_UPDATE_EVENT],
+ ("Failed to create event for DNS event (%d)\n", GetLastError()));
+
+ m->haDataEvent[DATA_SHUTDOWN_EVENT] = CreateEvent(NULL,
+ TRUE, FALSE, NULL);
+ AssertReleaseMsg(m->haDataEvent[DATA_SHUTDOWN_EVENT],
+ ("Failed to create event for Shutdown signal (%d)\n", GetLastError()));
+
+ LONG lrc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"),
+ 0, KEY_READ|KEY_NOTIFY, &m->hKeyTcpipParameters);
+ AssertReleaseMsg(lrc == ERROR_SUCCESS,
+ ("Failed to open Registry Key for read and update notifications (%d)\n",
+ GetLastError()));
+}
+
+
+HostDnsServiceWin::~HostDnsServiceWin()
+{
+ if (m && !m->hKeyTcpipParameters)
+ {
+ RegCloseKey(m->hKeyTcpipParameters);
+ m->hKeyTcpipParameters = 0;
+
+ CloseHandle(m->haDataEvent[DATA_DNS_UPDATE_EVENT]);
+ CloseHandle(m->haDataEvent[DATA_SHUTDOWN_EVENT]);
+
+ delete m;
+
+ m = NULL;
+ }
+}
+
+
+HRESULT HostDnsServiceWin::init()
+{
+ HRESULT hrc = HostDnsMonitor::init();
+ AssertComRCReturn(hrc, hrc);
+
+ return updateInfo();
+}
+
+
+void HostDnsServiceWin::monitorThreadShutdown()
+{
+ SetEvent(m->haDataEvent[DATA_SHUTDOWN_EVENT]);
+}
+
+
+int HostDnsServiceWin::monitorWorker()
+{
+ registerNotification(m->hKeyTcpipParameters,
+ m->haDataEvent[DATA_DNS_UPDATE_EVENT]);
+
+ monitorThreadInitializationDone();
+
+ DWORD dwRc;
+ while (true)
+ {
+ dwRc = WaitForMultipleObjects(DATA_MAX_EVENT,
+ m->haDataEvent,
+ FALSE,
+ INFINITE);
+ AssertMsgReturn(dwRc != WAIT_FAILED,
+ ("WaitForMultipleObjects failed (%d) to wait! Please debug",
+ GetLastError()), VERR_INTERNAL_ERROR);
+
+ if ((dwRc - WAIT_OBJECT_0) == DATA_DNS_UPDATE_EVENT)
+ {
+ updateInfo();
+ notifyAll();
+ ResetEvent(m->haDataEvent[DATA_DNS_UPDATE_EVENT]);
+ registerNotification(m->hKeyTcpipParameters,
+ m->haDataEvent[DATA_DNS_UPDATE_EVENT]);
+
+ }
+ else if ((dwRc - WAIT_OBJECT_0) == DATA_SHUTDOWN_EVENT)
+ {
+ break;
+ }
+ else
+ {
+ AssertMsgFailedReturn(
+ ("WaitForMultipleObjects returns out of bound index %d. Please debug!",
+ dwRc),
+ VERR_INTERNAL_ERROR);
+ }
+ }
+ return VINF_SUCCESS;
+}
+
+
+HRESULT HostDnsServiceWin::updateInfo()
+{
+ HRESULT hrc;
+ DWORD regIndex;
+ BYTE abDomain[256];
+ BYTE abNameServers[256];
+ BYTE abSearchList[256];
+
+ RT_ZERO(abDomain);
+ RT_ZERO(abNameServers);
+ RT_ZERO(abSearchList);
+
+ regIndex = 0;
+ do {
+ CHAR keyName[256];
+ DWORD cbKeyName = sizeof(keyName);
+ DWORD keyType = 0;
+ BYTE keyData[1024];
+ DWORD cbKeyData = sizeof(keyData);
+
+ hrc = RegEnumValueA(m->hKeyTcpipParameters, regIndex, keyName, &cbKeyName, 0,
+ &keyType, keyData, &cbKeyData);
+ if ( hrc == ERROR_SUCCESS
+ || hrc == ERROR_MORE_DATA)
+ {
+ if ( RTStrICmp("Domain", keyName) == 0
+ && cbKeyData > 1
+ && cbKeyData < sizeof(abDomain))
+ memcpy(abDomain, keyData, cbKeyData);
+
+ else if ( RTStrICmp("DhcpDomain", keyName) == 0
+ && cbKeyData > 1
+ && abDomain[0] == 0
+ && cbKeyData < sizeof(abDomain))
+ memcpy(abDomain, keyData, cbKeyData);
+
+ else if ( RTStrICmp("NameServer", keyName) == 0
+ && cbKeyData > 1
+ && cbKeyData < sizeof(abNameServers))
+ memcpy(abNameServers, keyData, cbKeyData);
+
+ else if ( RTStrICmp("DhcpNameServer", keyName) == 0
+ && cbKeyData > 1
+ && abNameServers[0] == 0
+ && cbKeyData < sizeof(abNameServers))
+ memcpy(abNameServers, keyData, cbKeyData);
+
+ else if ( RTStrICmp("SearchList", keyName) == 0
+ && cbKeyData > 1
+ && cbKeyData < sizeof(abSearchList))
+ memcpy(abSearchList, keyData, cbKeyData);
+ }
+ regIndex++;
+ } while (hrc != ERROR_NO_MORE_ITEMS);
+
+ /* OK, now parse and update DNS structures. */
+ /* domain name */
+ HostDnsInformation info;
+ info.domain = (char*)abDomain;
+
+ /* server list */
+ strList2List(info.servers, (char *)abNameServers);
+ /* search list */
+ strList2List(info.searchList, (char *)abSearchList);
+
+ HostDnsMonitor::setInfo(info);
+
+ return S_OK;
+}
+
+
+void HostDnsServiceWin::strList2List(std::vector<std::string>& lst, char *strLst)
+{
+ char *next, *current;
+ char address[512];
+
+ AssertPtrReturnVoid(strLst);
+
+ if (strlen(strLst) == 0)
+ return;
+
+ current = strLst;
+ do {
+ RT_ZERO(address);
+ next = RTStrStr(current, " ");
+
+ if (next)
+ strncpy(address, current, RT_MIN(sizeof(address)-1, next - current));
+ else
+ strcpy(address, current);
+
+ lst.push_back(std::string(address));
+
+ current = next + 1;
+ } while(next);
+
+}
diff --git a/src/VBox/Main/src-server/win/HostPowerWin.cpp b/src/VBox/Main/src-server/win/HostPowerWin.cpp
index ae806fd7..34826f9d 100644
--- a/src/VBox/Main/src-server/win/HostPowerWin.cpp
+++ b/src/VBox/Main/src-server/win/HostPowerWin.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -31,12 +31,12 @@ extern "C" {
static WCHAR gachWindowClassName[] = L"VBoxPowerNotifyClass";
-HostPowerServiceWin::HostPowerServiceWin(VirtualBox *aVirtualBox) : HostPowerService(aVirtualBox)
+HostPowerServiceWin::HostPowerServiceWin(VirtualBox *aVirtualBox) : HostPowerService(aVirtualBox), mThread(NIL_RTTHREAD)
{
mHwnd = 0;
- int rc = RTThreadCreate (&mThread, HostPowerServiceWin::NotificationThread, this, 65536,
- RTTHREADTYPE_GUI, RTTHREADFLAGS_WAITABLE, "MainPower");
+ int rc = RTThreadCreate(&mThread, HostPowerServiceWin::NotificationThread, this, 65536,
+ RTTHREADTYPE_GUI, RTTHREADFLAGS_WAITABLE, "MainPower");
if (RT_FAILURE(rc))
{
@@ -55,12 +55,14 @@ HostPowerServiceWin::~HostPowerServiceWin()
SetWindowLongPtr(mHwnd, 0, 0);
/* Send the quit message and wait for it be processed. */
SendMessage(mHwnd, WM_QUIT, 0, 0);
+ RTThreadWait(mThread, 5000, NULL);
+ mThread = NIL_RTTHREAD;
}
}
-DECLCALLBACK(int) HostPowerServiceWin::NotificationThread (RTTHREAD ThreadSelf, void *pInstance)
+DECLCALLBACK(int) HostPowerServiceWin::NotificationThread(RTTHREAD ThreadSelf, void *pInstance)
{
HostPowerServiceWin *pPowerObj = (HostPowerServiceWin *)pInstance;
HWND hwnd = 0;
@@ -68,7 +70,7 @@ DECLCALLBACK(int) HostPowerServiceWin::NotificationThread (RTTHREAD ThreadSelf,
/* Create a window and make it a power event notification handler. */
int rc = VINF_SUCCESS;
- HINSTANCE hInstance = (HINSTANCE)GetModuleHandle (NULL);
+ HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
/* Register the Window Class. */
WNDCLASS wc;
@@ -94,10 +96,10 @@ DECLCALLBACK(int) HostPowerServiceWin::NotificationThread (RTTHREAD ThreadSelf,
else
{
/* Create the window. */
- hwnd = pPowerObj->mHwnd = CreateWindowEx (WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
- gachWindowClassName, gachWindowClassName,
- WS_POPUPWINDOW,
- -200, -200, 100, 100, NULL, NULL, hInstance, NULL);
+ hwnd = pPowerObj->mHwnd = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
+ gachWindowClassName, gachWindowClassName,
+ WS_POPUPWINDOW,
+ -200, -200, 100, 100, NULL, NULL, hInstance, NULL);
if (hwnd == NULL)
{
@@ -121,11 +123,11 @@ DECLCALLBACK(int) HostPowerServiceWin::NotificationThread (RTTHREAD ThreadSelf,
Log(("HostPowerServiceWin::NotificationThread: exit thread\n"));
if (hwnd)
- DestroyWindow (hwnd);
+ DestroyWindow(hwnd);
if (atomWindowClass != 0)
{
- UnregisterClass (gachWindowClassName, hInstance);
+ UnregisterClass(gachWindowClassName, hInstance);
atomWindowClass = 0;
}
@@ -146,11 +148,11 @@ LRESULT CALLBACK HostPowerServiceWin::WndProc(HWND hwnd, UINT msg, WPARAM wParam
switch(wParam)
{
case PBT_APMSUSPEND:
- pPowerObj->notify(HostPowerEvent_Suspend);
+ pPowerObj->notify(Reason_HostSuspend);
break;
case PBT_APMRESUMEAUTOMATIC:
- pPowerObj->notify(HostPowerEvent_Resume);
+ pPowerObj->notify(Reason_HostResume);
break;
case PBT_APMPOWERSTATUSCHANGE:
@@ -177,27 +179,27 @@ LRESULT CALLBACK HostPowerServiceWin::WndProc(HWND hwnd, UINT msg, WPARAM wParam
if ( rc == 0 /* STATUS_SUCCESS */
&& BatteryState.EstimatedTime < 60*5)
{
- pPowerObj->notify(HostPowerEvent_BatteryLow);
+ pPowerObj->notify(Reason_HostBatteryLow);
}
}
else
/* If the machine has less than 5% battery left (and is not connected to the AC), then we should save the state. */
if (SystemPowerStatus.BatteryFlag == 4 /* critical battery status; less than 5% */)
{
- pPowerObj->notify(HostPowerEvent_BatteryLow);
+ pPowerObj->notify(Reason_HostBatteryLow);
}
}
}
break;
}
default:
- return DefWindowProc (hwnd, msg, wParam, lParam);
+ return DefWindowProc(hwnd, msg, wParam, lParam);
}
}
return TRUE;
}
default:
- return DefWindowProc (hwnd, msg, wParam, lParam);
+ return DefWindowProc(hwnd, msg, wParam, lParam);
}
}
diff --git a/src/VBox/Main/src-server/win/NetIf-win.cpp b/src/VBox/Main/src-server/win/NetIf-win.cpp
index cce820da..3b86dabd 100644
--- a/src/VBox/Main/src-server/win/NetIf-win.cpp
+++ b/src/VBox/Main/src-server/win/NetIf-win.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008-2010 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -954,7 +954,7 @@ static int vboxNetWinAddComponent(std::list<ComObjPtr<HostNetworkInterface> > *
if (hr == S_OK)
{
NETIFINFO Info;
- memset(&Info, 0, sizeof(Info));
+ RT_ZERO(Info);
Info.Uuid = *(Guid(IfGuid).raw());
rc = collectNetIfInfo(name, Guid(IfGuid), &Info, iDefaultInterface);
if (RT_FAILURE(rc))
@@ -1082,6 +1082,33 @@ int NetIfGetConfigByName(PNETIFINFO)
return VERR_NOT_IMPLEMENTED;
}
+/**
+ * Obtain the current state of the interface.
+ *
+ * @returns VBox status code.
+ *
+ * @param pcszIfName Interface name.
+ * @param penmState Where to store the retrieved state.
+ */
+int NetIfGetState(const char *pcszIfName, NETIFSTATUS *penmState)
+{
+ return VERR_NOT_IMPLEMENTED;
+}
+
+/**
+ * Retrieve the physical link speed in megabits per second. If the interface is
+ * not up or otherwise unavailable the zero speed is returned.
+ *
+ * @returns VBox status code.
+ *
+ * @param pcszIfName Interface name.
+ * @param puMbits Where to store the link speed.
+ */
+int NetIfGetLinkSpeed(const char * /*pcszIfName*/, uint32_t * /*puMbits*/)
+{
+ return VERR_NOT_IMPLEMENTED;
+}
+
int NetIfCreateHostOnlyNetworkInterface(VirtualBox *pVBox,
IHostNetworkInterface **aHostNetworkInterface,
IProgress **aProgress,
@@ -1485,7 +1512,7 @@ int NetIfList(std::list<ComObjPtr<HostNetworkInterface> > &list)
{
hr = pBp->EnumBindingInterfaces(&pEnumBi);
Assert(hr == S_OK);
- if ( hr == S_OK )
+ if (hr == S_OK)
{
hr = pEnumBi->Reset();
Assert(hr == S_OK);
@@ -1493,7 +1520,7 @@ int NetIfList(std::list<ComObjPtr<HostNetworkInterface> > &list)
{
while ((hr = pEnumBi->Next(1, &pBi, NULL)) == S_OK)
{
- hr = pBi->GetLowerComponent( &pMpNcc );
+ hr = pBi->GetLowerComponent(&pMpNcc);
Assert(hr == S_OK);
if (hr == S_OK)
{
@@ -1527,7 +1554,7 @@ int NetIfList(std::list<ComObjPtr<HostNetworkInterface> > &list)
}
else
{
- LogRel(("failed to get the sun_VBoxNetFlt component, error (0x%x)", hr));
+ LogRel(("failed to get the sun_VBoxNetFlt component, error (0x%x)\n", hr));
}
VBoxNetCfgWinReleaseINetCfg(pNc, FALSE);
diff --git a/src/VBox/Main/src-server/win/PerformanceWin.cpp b/src/VBox/Main/src-server/win/PerformanceWin.cpp
index 48643c6d..74c2bf13 100644
--- a/src/VBox/Main/src-server/win/PerformanceWin.cpp
+++ b/src/VBox/Main/src-server/win/PerformanceWin.cpp
@@ -6,7 +6,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -33,8 +33,10 @@ extern "C" {
}
#include <iprt/err.h>
+#include <iprt/ldr.h>
#include <iprt/mp.h>
#include <iprt/mem.h>
+#include <iprt/system.h>
#include <map>
@@ -61,6 +63,7 @@ public:
virtual int getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle);
virtual int getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total);
+
private:
struct VMProcessStats
{
@@ -72,21 +75,20 @@ private:
typedef std::map<RTPROCESS, VMProcessStats> VMProcessMap;
- VMProcessMap mProcessStats;
+ VMProcessMap mProcessStats;
- typedef BOOL (WINAPI *PFNGST)(
- LPFILETIME lpIdleTime,
- LPFILETIME lpKernelTime,
- LPFILETIME lpUserTime);
- typedef NTSTATUS (WINAPI *PFNNQSI)(
- SYSTEM_INFORMATION_CLASS SystemInformationClass,
- PVOID SystemInformation,
- ULONG SystemInformationLength,
- PULONG ReturnLength);
+ typedef BOOL (WINAPI *PFNGST)(LPFILETIME lpIdleTime,
+ LPFILETIME lpKernelTime,
+ LPFILETIME lpUserTime);
+ typedef NTSTATUS (WINAPI *PFNNQSI)(SYSTEM_INFORMATION_CLASS SystemInformationClass,
+ PVOID SystemInformation,
+ ULONG SystemInformationLength,
+ PULONG ReturnLength);
PFNGST mpfnGetSystemTimes;
PFNNQSI mpfnNtQuerySystemInformation;
- HMODULE mhNtDll;
+
+ ULONG totalRAM;
};
CollectorHAL *createHAL()
@@ -94,35 +96,29 @@ CollectorHAL *createHAL()
return new CollectorWin();
}
-CollectorWin::CollectorWin() : CollectorHAL(), mhNtDll(0)
+CollectorWin::CollectorWin() : CollectorHAL(), mpfnNtQuerySystemInformation(NULL)
{
- mpfnGetSystemTimes = (PFNGST)GetProcAddress(
- GetModuleHandle(TEXT("kernel32.dll")),
- "GetSystemTimes");
+ /* Note! Both kernel32.dll and ntdll.dll can be assumed to always be present. */
+ mpfnGetSystemTimes = (PFNGST)RTLdrGetSystemSymbol("kernel32.dll", "GetSystemTimes");
if (!mpfnGetSystemTimes)
{
/* Fall back to deprecated NtQuerySystemInformation */
- if (!(mhNtDll = LoadLibrary(TEXT("ntdll.dll"))))
- {
- LogRel(("Failed to load NTDLL.DLL with error 0x%x. GetSystemTimes() is"
- " not available either. CPU and VM metrics will not be collected.\n",
- GetLastError()));
- mpfnNtQuerySystemInformation = 0;
- }
- else if (!(mpfnNtQuerySystemInformation = (PFNNQSI)GetProcAddress(mhNtDll,
- "NtQuerySystemInformation")))
- {
- LogRel(("Neither GetSystemTimes() nor NtQuerySystemInformation() is"
- " not available. CPU and VM metrics will not be collected.\n"));
- mpfnNtQuerySystemInformation = 0;
- }
+ mpfnNtQuerySystemInformation = (PFNNQSI)RTLdrGetSystemSymbol("ntdll.dll", "NtQuerySystemInformation");
+ if (!mpfnNtQuerySystemInformation)
+ LogRel(("Warning! Neither GetSystemTimes() nor NtQuerySystemInformation() is not available.\n"
+ " CPU and VM metrics will not be collected! (lasterr %u)\n", GetLastError()));
}
+
+ uint64_t cb;
+ int rc = RTSystemQueryTotalRam(&cb);
+ if (RT_FAILURE(rc))
+ totalRAM = 0;
+ else
+ totalRAM = (ULONG)(cb / 1024);
}
CollectorWin::~CollectorWin()
{
- if (mhNtDll)
- FreeLibrary(mhNtDll);
}
#define FILETTIME_TO_100NS(ft) (((uint64_t)ft.dwHighDateTime << 32) + ft.dwLowDateTime)
@@ -278,7 +274,7 @@ int CollectorWin::getHostCpuMHz(ULONG *mhz)
return VERR_NO_MEMORY;
LONG ns = CallNtPowerInformation(ProcessorInformation, NULL, 0, ppi,
- nProcessors * sizeof(PROCESSOR_POWER_INFORMATION));
+ nProcessors * sizeof(PROCESSOR_POWER_INFORMATION));
if (ns)
{
Log(("CallNtPowerInformation() -> %x\n", ns));
@@ -300,19 +296,16 @@ int CollectorWin::getHostCpuMHz(ULONG *mhz)
int CollectorWin::getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available)
{
- MEMORYSTATUSEX mstat;
-
- mstat.dwLength = sizeof(mstat);
- if (GlobalMemoryStatusEx(&mstat))
+ AssertReturn(totalRAM, VERR_INTERNAL_ERROR);
+ uint64_t cb;
+ int rc = RTSystemQueryAvailableRam(&cb);
+ if (RT_SUCCESS(rc))
{
- *total = (ULONG)( mstat.ullTotalPhys / 1024 );
- *available = (ULONG)( mstat.ullAvailPhys / 1024 );
+ *total = totalRAM;
+ *available = (ULONG)(cb / 1024);
*used = *total - *available;
}
- else
- return RTErrConvertFromWin32(GetLastError());
-
- return VINF_SUCCESS;
+ return rc;
}
int CollectorWin::getProcessCpuLoad(RTPROCESS process, ULONG *user, ULONG *kernel)
@@ -348,9 +341,4 @@ int CollectorWin::getProcessMemoryUsage(RTPROCESS process, ULONG *used)
return VINF_SUCCESS;
}
-int getDiskListByFs(const char *name, DiskList& list)
-{
- return VERR_NOT_IMPLEMENTED;
-}
-
}
diff --git a/src/VBox/Main/src-server/win/svchlp.cpp b/src/VBox/Main/src-server/win/svchlp.cpp
index 2191f3fa..a3c07ff6 100644
--- a/src/VBox/Main/src-server/win/svchlp.cpp
+++ b/src/VBox/Main/src-server/win/svchlp.cpp
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Main/src-server/win/svchlp.h b/src/VBox/Main/src-server/win/svchlp.h
index 0e8b8b80..a5df8dba 100644
--- a/src/VBox/Main/src-server/win/svchlp.h
+++ b/src/VBox/Main/src-server/win/svchlp.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Main/src-server/win/svcmain.cpp b/src/VBox/Main/src-server/win/svcmain.cpp
index 111c2dd4..5e2c251b 100644
--- a/src/VBox/Main/src-server/win/svcmain.cpp
+++ b/src/VBox/Main/src-server/win/svcmain.cpp
@@ -327,19 +327,26 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpC
* registering/unregistering or calling the helper functionality. */
if (fRun)
{
+ /** @todo Merge this code with server.cpp (use Logging.cpp?). */
+ char szLogFile[RTPATH_MAX];
if (!pszLogFile)
{
- char szLogFile[RTPATH_MAX];
vrc = com::GetVBoxUserHomeDirectory(szLogFile, sizeof(szLogFile));
if (RT_SUCCESS(vrc))
vrc = RTPathAppend(szLogFile, sizeof(szLogFile), "VBoxSVC.log");
- if (RT_SUCCESS(vrc))
- pszLogFile = RTStrDup(szLogFile);
}
+ else
+ {
+ if (!RTStrPrintf(szLogFile, sizeof(szLogFile), "%s", pszLogFile))
+ vrc = VERR_NO_MEMORY;
+ }
+ if (RT_FAILURE(vrc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to create logging file name, rc=%Rrc", vrc);
+
char szError[RTPATH_MAX + 128];
- vrc = com::VBoxLogRelCreate("COM Server", pszLogFile,
+ vrc = com::VBoxLogRelCreate("COM Server", szLogFile,
RTLOGFLAGS_PREFIX_THREAD | RTLOGFLAGS_PREFIX_TIME_PROG,
- "all", "VBOXSVC_RELEASE_LOG",
+ VBOXSVC_LOG_DEFAULT, "VBOXSVC_RELEASE_LOG",
RTLOGDEST_FILE, UINT32_MAX /* cMaxEntriesPerGroup */,
cHistory, uHistoryFileTime, uHistoryFileSize,
szError, sizeof(szError));
diff --git a/src/VBox/Main/src-server/xpcom/server.cpp b/src/VBox/Main/src-server/xpcom/server.cpp
index 6c48fcba..24ff15a8 100644
--- a/src/VBox/Main/src-server/xpcom/server.cpp
+++ b/src/VBox/Main/src-server/xpcom/server.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2004-2012 Oracle Corporation
+ * Copyright (C) 2004-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -20,10 +20,6 @@
#include <nsIComponentRegistrar.h>
-#ifdef XPCOM_GLUE
-# include <nsXPCOMGlue.h>
-#endif
-
#include <nsEventQueueUtils.h>
#include <nsGenericFactory.h>
@@ -66,7 +62,7 @@
#include "AudioAdapterImpl.h"
#include "BandwidthControlImpl.h"
#include "BandwidthGroupImpl.h"
-#include "DHCPServerRunner.h"
+#include "NetworkServiceRunner.h"
#include "DHCPServerImpl.h"
#include "GuestOSTypeImpl.h"
#include "HostImpl.h"
@@ -77,7 +73,6 @@
#include "NATEngineImpl.h"
#include "NetworkAdapterImpl.h"
#include "ParallelPortImpl.h"
-#include "ProgressCombinedImpl.h"
#include "ProgressProxyImpl.h"
#include "SerialPortImpl.h"
#include "SharedFolderImpl.h"
@@ -85,6 +80,7 @@
#include "StorageControllerImpl.h"
#include "SystemPropertiesImpl.h"
#include "USBControllerImpl.h"
+#include "USBDeviceFiltersImpl.h"
#include "VFSExplorerImpl.h"
#include "VirtualBoxImpl.h"
#include "VRDEServerImpl.h"
@@ -96,6 +92,8 @@
#ifdef VBOX_WITH_EXTPACK
# include "ExtPackManagerImpl.h"
#endif
+# include "NATNetworkImpl.h"
+
/* implement nsISupports parts of our objects with support for nsIClassInfo */
@@ -126,18 +124,12 @@ NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Snapshot, ISnapshot)
NS_DECL_CLASSINFO(Medium)
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Medium, IMedium)
-NS_DECL_CLASSINFO(MediumFormat)
-NS_IMPL_THREADSAFE_ISUPPORTS1_CI(MediumFormat, IMediumFormat)
-
NS_DECL_CLASSINFO(MediumAttachment)
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(MediumAttachment, IMediumAttachment)
NS_DECL_CLASSINFO(Progress)
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Progress, IProgress)
-NS_DECL_CLASSINFO(CombinedProgress)
-NS_IMPL_THREADSAFE_ISUPPORTS1_CI(CombinedProgress, IProgress)
-
NS_DECL_CLASSINFO(ProgressProxy)
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(ProgressProxy, IProgress)
@@ -156,6 +148,9 @@ NS_IMPL_THREADSAFE_ISUPPORTS1_CI(HostNetworkInterface, IHostNetworkInterface)
NS_DECL_CLASSINFO(DHCPServer)
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(DHCPServer, IDHCPServer)
+NS_DECL_CLASSINFO(NATNetwork)
+NS_IMPL_THREADSAFE_ISUPPORTS1_CI(NATNetwork, INATNetwork)
+
NS_DECL_CLASSINFO(GuestOSType)
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(GuestOSType, IGuestOSType)
@@ -175,6 +170,9 @@ NS_IMPL_THREADSAFE_ISUPPORTS1_CI(ParallelPort, IParallelPort)
NS_DECL_CLASSINFO(USBController)
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(USBController, IUSBController)
+NS_DECL_CLASSINFO(USBDeviceFilters)
+NS_IMPL_THREADSAFE_ISUPPORTS1_CI(USBDeviceFilters, IUSBDeviceFilters)
+
NS_DECL_CLASSINFO(StorageController)
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(StorageController, IStorageController)
@@ -881,23 +879,26 @@ int main(int argc, char **argv)
nsresult rc;
+ /** @todo Merge this code with svcmain.cpp (use Logging.cpp?). */
+ char szLogFile[RTPATH_MAX];
if (!pszLogFile)
{
- char szLogFile[RTPATH_MAX] = "";
vrc = com::GetVBoxUserHomeDirectory(szLogFile, sizeof(szLogFile));
- if (vrc == VERR_ACCESS_DENIED)
- return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to open global settings directory '%s'", szLogFile);
if (RT_SUCCESS(vrc))
vrc = RTPathAppend(szLogFile, sizeof(szLogFile), "VBoxSVC.log");
- if (RT_SUCCESS(vrc))
- pszLogFile = RTStrDup(szLogFile);
- if (RT_FAILURE(vrc))
- return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to determine release log file (%Rrc)", vrc);
}
+ else
+ {
+ if (!RTStrPrintf(szLogFile, sizeof(szLogFile), "%s", pszLogFile))
+ vrc = VERR_NO_MEMORY;
+ }
+ if (RT_FAILURE(vrc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to create logging file name, rc=%Rrc", vrc);
+
char szError[RTPATH_MAX + 128];
- vrc = com::VBoxLogRelCreate("XPCOM Server", pszLogFile,
+ vrc = com::VBoxLogRelCreate("XPCOM Server", szLogFile,
RTLOGFLAGS_PREFIX_THREAD | RTLOGFLAGS_PREFIX_TIME_PROG,
- "all", "VBOXSVC_RELEASE_LOG",
+ VBOXSVC_LOG_DEFAULT, "VBOXSVC_RELEASE_LOG",
RTLOGDEST_FILE, UINT32_MAX /* cMaxEntriesPerGroup */,
cHistory, uHistoryFileTime, uHistoryFileSize,
szError, sizeof(szError));
diff --git a/src/VBox/Main/src-server/xpcom/server.h b/src/VBox/Main/src-server/xpcom/server.h
index f14977af..4fbaa231 100644
--- a/src/VBox/Main/src-server/xpcom/server.h
+++ b/src/VBox/Main/src-server/xpcom/server.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Main/src-server/xpcom/server_module.cpp b/src/VBox/Main/src-server/xpcom/server_module.cpp
index 0647016c..11cf239e 100644
--- a/src/VBox/Main/src-server/xpcom/server_module.cpp
+++ b/src/VBox/Main/src-server/xpcom/server_module.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2014 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -53,10 +53,9 @@
#include <iprt/path.h>
#include <iprt/process.h>
#include <iprt/env.h>
+#include <iprt/string.h>
#include <iprt/thread.h>
-#include <string.h>
-
#if defined(RT_OS_SOLARIS)
# include <sys/systeminfo.h>
#endif
@@ -92,8 +91,8 @@ static bool IsVBoxSVCPathSet = false;
* in sync with macros used for VirtualBox in server.cpp for the same purpose.
*/
-NS_DECL_CLASSINFO (VirtualBox)
-NS_IMPL_CI_INTERFACE_GETTER1 (VirtualBox, IVirtualBox)
+NS_DECL_CLASSINFO(VirtualBox)
+NS_IMPL_CI_INTERFACE_GETTER1(VirtualBox, IVirtualBox)
static nsresult vboxsvcSpawnDaemon(void)
{
@@ -137,7 +136,7 @@ static nsresult vboxsvcSpawnDaemon(void)
writable = nsnull;
char msg[10];
- memset(msg, '\0', sizeof(msg));
+ RT_ZERO(msg);
if ( PR_Read(readable, msg, sizeof(msg)-1) != 5
|| strcmp(msg, "READY"))
{
@@ -168,8 +167,8 @@ end:
* VirtualBox component defined on the server.
*/
static NS_IMETHODIMP
-VirtualBoxConstructor (nsISupports *aOuter, REFNSIID aIID,
- void **aResult)
+VirtualBoxConstructor(nsISupports *aOuter, REFNSIID aIID,
+ void **aResult)
{
LogFlowFuncEnter();
@@ -189,25 +188,25 @@ VirtualBoxConstructor (nsISupports *aOuter, REFNSIID aIID,
{
/* Get the directory containing XPCOM components -- the VBoxSVC
* executable is expected in the parent directory. */
- nsCOMPtr <nsIProperties> dirServ = do_GetService (NS_DIRECTORY_SERVICE_CONTRACTID, &rc);
+ nsCOMPtr<nsIProperties> dirServ = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rc);
if (NS_SUCCEEDED(rc))
{
- nsCOMPtr <nsIFile> componentDir;
- rc = dirServ->Get (NS_XPCOM_COMPONENT_DIR,
- NS_GET_IID (nsIFile), getter_AddRefs (componentDir));
+ nsCOMPtr<nsIFile> componentDir;
+ rc = dirServ->Get(NS_XPCOM_COMPONENT_DIR,
+ NS_GET_IID(nsIFile), getter_AddRefs(componentDir));
if (NS_SUCCEEDED(rc))
{
nsCAutoString path;
- componentDir->GetNativePath (path);
+ componentDir->GetNativePath(path);
- LogFlowFunc (("component directory = \"%s\"\n", path.get()));
- AssertBreakStmt (path.Length() + strlen (VBoxSVC_exe) < RTPATH_MAX,
- rc = NS_ERROR_FAILURE);
+ LogFlowFunc(("component directory = \"%s\"\n", path.get()));
+ AssertBreakStmt(path.Length() + strlen(VBoxSVC_exe) < RTPATH_MAX,
+ rc = NS_ERROR_FAILURE);
#if defined(RT_OS_SOLARIS) && defined(VBOX_WITH_HARDENING)
char achKernArch[128];
- int cbKernArch = sysinfo (SI_ARCHITECTURE_K, achKernArch, sizeof(achKernArch));
+ int cbKernArch = sysinfo(SI_ARCHITECTURE_K, achKernArch, sizeof(achKernArch));
if (cbKernArch > 0)
{
sprintf(VBoxSVCPath, "/opt/VirtualBox/%s%s", achKernArch, VBoxSVC_exe);
@@ -216,9 +215,9 @@ VirtualBoxConstructor (nsISupports *aOuter, REFNSIID aIID,
else
rc = NS_ERROR_UNEXPECTED;
#else
- strcpy (VBoxSVCPath, path.get());
- RTPathStripFilename (VBoxSVCPath);
- strcat (VBoxSVCPath, VBoxSVC_exe);
+ strcpy(VBoxSVCPath, path.get());
+ RTPathStripFilename(VBoxSVCPath);
+ strcat(VBoxSVCPath, VBoxSVC_exe);
IsVBoxSVCPathSet = true;
#endif
@@ -228,7 +227,7 @@ VirtualBoxConstructor (nsISupports *aOuter, REFNSIID aIID,
break;
}
- nsCOMPtr <ipcIService> ipcServ = do_GetService (IPC_SERVICE_CONTRACTID, &rc);
+ nsCOMPtr<ipcIService> ipcServ = do_GetService(IPC_SERVICE_CONTRACTID, &rc);
if (NS_FAILED(rc))
break;
@@ -239,13 +238,13 @@ VirtualBoxConstructor (nsISupports *aOuter, REFNSIID aIID,
do
{
- LogFlowFunc (("Resolving server name \"%s\"...\n", VBOXSVC_IPC_NAME));
+ LogFlowFunc(("Resolving server name \"%s\"...\n", VBOXSVC_IPC_NAME));
PRUint32 serverID = 0;
- rc = ipcServ->ResolveClientName (VBOXSVC_IPC_NAME, &serverID);
+ rc = ipcServ->ResolveClientName(VBOXSVC_IPC_NAME, &serverID);
if (NS_FAILED(rc))
{
- LogFlowFunc (("Starting server \"%s\"...\n", VBoxSVCPath));
+ LogFlowFunc(("Starting server \"%s\"...\n", VBoxSVCPath));
startedOnce = true;
@@ -256,8 +255,8 @@ VirtualBoxConstructor (nsISupports *aOuter, REFNSIID aIID,
/* wait for the server process to establish a connection */
do
{
- RTThreadSleep (VBoxSVC_WaitSlice);
- rc = ipcServ->ResolveClientName (VBOXSVC_IPC_NAME, &serverID);
+ RTThreadSleep(VBoxSVC_WaitSlice);
+ rc = ipcServ->ResolveClientName(VBOXSVC_IPC_NAME, &serverID);
if (NS_SUCCEEDED(rc))
break;
if (timeLeft <= VBoxSVC_WaitSlice)
@@ -276,20 +275,20 @@ VirtualBoxConstructor (nsISupports *aOuter, REFNSIID aIID,
}
}
- LogFlowFunc (("Connecting to server (ID=%d)...\n", serverID));
+ LogFlowFunc(("Connecting to server (ID=%d)...\n", serverID));
- nsCOMPtr <ipcIDConnectService> dconServ =
- do_GetService (IPC_DCONNECTSERVICE_CONTRACTID, &rc);
+ nsCOMPtr<ipcIDConnectService> dconServ =
+ do_GetService(IPC_DCONNECTSERVICE_CONTRACTID, &rc);
if (NS_FAILED(rc))
break;
- rc = dconServ->CreateInstance (serverID,
- CLSID_VirtualBox,
- aIID, aResult);
+ rc = dconServ->CreateInstance(serverID,
+ CLSID_VirtualBox,
+ aIID, aResult);
if (NS_SUCCEEDED(rc))
break;
- LogFlowFunc (("Failed to connect (rc=%Rhrc (%#08x))\n", rc, rc));
+ LogFlowFunc(("Failed to connect (rc=%Rhrc (%#08x))\n", rc, rc));
/* It's possible that the server gets shut down after we
* successfully resolve the server name but before it
@@ -298,12 +297,11 @@ VirtualBoxConstructor (nsISupports *aOuter, REFNSIID aIID,
if (!startedOnce)
{
nsresult rc2 =
- ipcServ->ResolveClientName (VBOXSVC_IPC_NAME, &serverID);
+ ipcServ->ResolveClientName(VBOXSVC_IPC_NAME, &serverID);
if (NS_SUCCEEDED(rc2))
break;
- LogFlowFunc (("Server seems to have terminated before "
- "receiving our request. Will try again.\n"));
+ LogFlowFunc(("Server seems to have terminated before receiving our request. Will try again.\n"));
}
else
break;
@@ -312,7 +310,7 @@ VirtualBoxConstructor (nsISupports *aOuter, REFNSIID aIID,
}
while (0);
- LogFlowFunc (("rc=%Rhrc (%#08x), vrc=%Rrc\n", rc, rc, vrc));
+ LogFlowFunc(("rc=%Rhrc (%#08x), vrc=%Rrc\n", rc, rc, vrc));
LogFlowFuncLeave();
return rc;
@@ -331,19 +329,19 @@ VirtualBoxConstructor (nsISupports *aOuter, REFNSIID aIID,
* @return
*/
static NS_IMETHODIMP
-VirtualBoxRegistration (nsIComponentManager *aCompMgr,
- nsIFile *aPath,
- const char *aLoaderStr,
- const char *aType,
- const nsModuleComponentInfo *aInfo)
+VirtualBoxRegistration(nsIComponentManager *aCompMgr,
+ nsIFile *aPath,
+ const char *aLoaderStr,
+ const char *aType,
+ const nsModuleComponentInfo *aInfo)
{
nsCAutoString modulePath;
- aPath->GetNativePath (modulePath);
+ aPath->GetNativePath(modulePath);
nsCAutoString moduleTarget;
- aPath->GetNativeTarget (moduleTarget);
+ aPath->GetNativeTarget(moduleTarget);
- LogFlowFunc (("aPath=%s, aTarget=%s, aLoaderStr=%s, aType=%s\n",
- modulePath.get(), moduleTarget.get(), aLoaderStr, aType));
+ LogFlowFunc(("aPath=%s, aTarget=%s, aLoaderStr=%s, aType=%s\n",
+ modulePath.get(), moduleTarget.get(), aLoaderStr, aType));
nsresult rc = NS_OK;
@@ -372,4 +370,4 @@ static const nsModuleComponentInfo components[] =
}
};
-NS_IMPL_NSGETMODULE (VirtualBox_Server_Module, components)
+NS_IMPL_NSGETMODULE(VirtualBox_Server_Module, components)