summaryrefslogtreecommitdiff
path: root/src/VBox/Main/src-server/VirtualBoxImpl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Main/src-server/VirtualBoxImpl.cpp')
-rw-r--r--src/VBox/Main/src-server/VirtualBoxImpl.cpp1235
1 files changed, 552 insertions, 683 deletions
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: */