VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/HostImpl.cpp@ 85769

Last change on this file since 85769 was 85769, checked in by vboxsync, 5 years ago

Main: bugref:9618 Added Main/API support for AMD-V Virtualized VMSAVE/VMLOAD hardware virtualization feature.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 127.1 KB
Line 
1/* $Id: HostImpl.cpp 85769 2020-08-14 12:59:51Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation: Host
4 */
5
6/*
7 * Copyright (C) 2004-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#define LOG_GROUP LOG_GROUP_MAIN_HOST
19
20#define __STDC_LIMIT_MACROS
21#define __STDC_CONSTANT_MACROS
22
23// VBoxNetCfg-win.h needs winsock2.h and thus MUST be included before any other
24// header file includes Windows.h.
25#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
26# include <VBox/VBoxNetCfg-win.h>
27#endif
28
29// for some reason Windows burns in sdk\...\winsock.h if this isn't included first
30#include "VBox/com/ptr.h"
31
32#include "HostImpl.h"
33
34#ifdef VBOX_WITH_USB
35# include "HostUSBDeviceImpl.h"
36# include "USBDeviceFilterImpl.h"
37# include "USBProxyService.h"
38#else
39# include "VirtualBoxImpl.h"
40#endif // VBOX_WITH_USB
41
42#include "HostNetworkInterfaceImpl.h"
43#include "HostVideoInputDeviceImpl.h"
44#include "MachineImpl.h"
45#include "AutoCaller.h"
46#include "LoggingNew.h"
47#include "Performance.h"
48#include "HostUpdateImpl.h"
49
50#include "MediumImpl.h"
51#include "HostPower.h"
52
53#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
54# include <HostHardwareLinux.h>
55#endif
56
57#include <set>
58
59#ifdef VBOX_WITH_RESOURCE_USAGE_API
60# include "PerformanceImpl.h"
61#endif /* VBOX_WITH_RESOURCE_USAGE_API */
62
63#if defined(RT_OS_DARWIN) && ARCH_BITS == 32
64# include <sys/types.h>
65# include <sys/sysctl.h>
66#endif
67
68#ifdef RT_OS_LINUX
69# include <sys/ioctl.h>
70# include <errno.h>
71# include <net/if.h>
72# include <net/if_arp.h>
73#endif /* RT_OS_LINUX */
74
75#ifdef RT_OS_SOLARIS
76# include <fcntl.h>
77# include <unistd.h>
78# include <stropts.h>
79# include <errno.h>
80# include <limits.h>
81# include <stdio.h>
82# include <libdevinfo.h>
83# include <sys/mkdev.h>
84# include <sys/scsi/generic/inquiry.h>
85# include <net/if.h>
86# include <sys/socket.h>
87# include <sys/sockio.h>
88# include <net/if_arp.h>
89# include <net/if.h>
90# include <sys/types.h>
91# include <sys/stat.h>
92# include <sys/cdio.h>
93# include <sys/dkio.h>
94# include <sys/mnttab.h>
95# include <sys/mntent.h>
96/* Dynamic loading of libhal on Solaris hosts */
97# ifdef VBOX_USE_LIBHAL
98# include "vbox-libhal.h"
99extern "C" char *getfullrawname(char *);
100# endif
101# include "solaris/DynLoadLibSolaris.h"
102
103/**
104 * Solaris DVD drive list as returned by getDVDInfoFromDevTree().
105 */
106typedef struct SOLARISDVD
107{
108 struct SOLARISDVD *pNext;
109 char szDescription[512];
110 char szRawDiskPath[PATH_MAX];
111} SOLARISDVD;
112/** Pointer to a Solaris DVD descriptor. */
113typedef SOLARISDVD *PSOLARISDVD;
114
115
116
117#endif /* RT_OS_SOLARIS */
118
119#ifdef RT_OS_WINDOWS
120# define _WIN32_DCOM
121# include <iprt/win/windows.h>
122# include <shellapi.h>
123# define INITGUID
124# include <guiddef.h>
125# include <devguid.h>
126# include <iprt/win/objbase.h>
127//# include <iprt/win/setupapi.h>
128# include <iprt/win/shlobj.h>
129# include <cfgmgr32.h>
130# include <tchar.h>
131#endif /* RT_OS_WINDOWS */
132
133#ifdef RT_OS_DARWIN
134# include "darwin/iokit.h"
135#endif
136
137#include <iprt/asm-amd64-x86.h>
138#include <iprt/string.h>
139#include <iprt/mp.h>
140#include <iprt/time.h>
141#include <iprt/param.h>
142#include <iprt/env.h>
143#include <iprt/mem.h>
144#include <iprt/system.h>
145#ifndef RT_OS_WINDOWS
146# include <iprt/path.h>
147#endif
148#ifdef RT_OS_SOLARIS
149# include <iprt/ctype.h>
150#endif
151#ifdef VBOX_WITH_HOSTNETIF_API
152# include "netif.h"
153#endif
154
155#include <VBox/usb.h>
156#include <VBox/err.h>
157#include <VBox/settings.h>
158#include <VBox/sup.h>
159#include <iprt/x86.h>
160
161#include "VBox/com/MultiResult.h"
162#include "VBox/com/array.h"
163
164#include <stdio.h>
165
166#include <algorithm>
167#include <iprt/sanitized/string>
168#include <vector>
169
170#include "HostDnsService.h"
171
172////////////////////////////////////////////////////////////////////////////////
173//
174// Host private data definition
175//
176////////////////////////////////////////////////////////////////////////////////
177
178struct Host::Data
179{
180 Data()
181 :
182 fDVDDrivesListBuilt(false),
183 fFloppyDrivesListBuilt(false),
184 fPersistentConfigUpToDate(false)
185 {};
186
187 VirtualBox *pParent;
188
189 HostNetworkInterfaceList llNetIfs; // list of network interfaces
190
191#ifdef VBOX_WITH_USB
192 USBDeviceFilterList llChildren; // all USB device filters
193 USBDeviceFilterList llUSBDeviceFilters; // USB device filters in use by the USB proxy service
194
195 /** Pointer to the USBProxyService object. */
196 USBProxyService *pUSBProxyService;
197#endif /* VBOX_WITH_USB */
198
199 // list of host drives; lazily created by getDVDDrives() and getFloppyDrives(),
200 // and protected by the medium tree lock handle (including the bools).
201 MediaList llDVDDrives,
202 llFloppyDrives;
203 bool fDVDDrivesListBuilt,
204 fFloppyDrivesListBuilt;
205
206#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
207 /** Object with information about host drives */
208 VBoxMainDriveInfo hostDrives;
209#endif
210
211 /** @name Features that can be queried with GetProcessorFeature.
212 * @{ */
213 bool fVTSupported,
214 fLongModeSupported,
215 fPAESupported,
216 fNestedPagingSupported,
217 fUnrestrictedGuestSupported,
218 fNestedHWVirtSupported,
219 fVirtVmsaveVmload,
220 fRecheckVTSupported;
221
222 /** @} */
223
224 /** 3D hardware acceleration supported? Tristate, -1 meaning not probed. */
225 int f3DAccelerationSupported;
226
227 HostPowerService *pHostPowerService;
228 /** Host's DNS informaton fetching */
229 HostDnsMonitorProxy hostDnsMonitorProxy;
230
231 /** Startup syncing of persistent config in extra data */
232 bool fPersistentConfigUpToDate;
233
234 /** The reference to the update check handler singleton. */
235 const ComObjPtr<HostUpdate> pHostUpdate;
236};
237
238
239////////////////////////////////////////////////////////////////////////////////
240//
241// Constructor / destructor
242//
243////////////////////////////////////////////////////////////////////////////////
244DEFINE_EMPTY_CTOR_DTOR(Host)
245
246HRESULT Host::FinalConstruct()
247{
248 return BaseFinalConstruct();
249}
250
251void Host::FinalRelease()
252{
253 uninit();
254 BaseFinalRelease();
255}
256
257/**
258 * Initializes the host object.
259 *
260 * @param aParent VirtualBox parent object.
261 */
262HRESULT Host::init(VirtualBox *aParent)
263{
264 HRESULT hrc;
265 LogFlowThisFunc(("aParent=%p\n", aParent));
266
267 /* Enclose the state transition NotReady->InInit->Ready */
268 AutoInitSpan autoInitSpan(this);
269 AssertReturn(autoInitSpan.isOk(), E_FAIL);
270
271 m = new Data();
272
273 m->pParent = aParent;
274
275#ifdef VBOX_WITH_USB
276 /*
277 * Create and initialize the USB Proxy Service.
278 */
279 m->pUSBProxyService = new USBProxyService(this);
280 hrc = m->pUSBProxyService->init();
281 AssertComRCReturn(hrc, hrc);
282#endif /* VBOX_WITH_USB */
283
284#ifdef VBOX_WITH_RESOURCE_USAGE_API
285 i_registerMetrics(aParent->i_performanceCollector());
286#endif /* VBOX_WITH_RESOURCE_USAGE_API */
287 /* Create the list of network interfaces so their metrics get registered. */
288 i_updateNetIfList();
289
290 m->hostDnsMonitorProxy.init(m->pParent);
291
292 hrc = unconst(m->pHostUpdate).createObject();
293 if (SUCCEEDED(hrc))
294 hrc = m->pHostUpdate->init(m->pParent);
295 AssertComRCReturn(hrc, hrc);
296
297#if defined(RT_OS_WINDOWS)
298 m->pHostPowerService = new HostPowerServiceWin(m->pParent);
299#elif defined(RT_OS_LINUX) && defined(VBOX_WITH_DBUS)
300 m->pHostPowerService = new HostPowerServiceLinux(m->pParent);
301#elif defined(RT_OS_DARWIN)
302 m->pHostPowerService = new HostPowerServiceDarwin(m->pParent);
303#else
304 m->pHostPowerService = new HostPowerService(m->pParent);
305#endif
306
307 /* Cache the features reported by GetProcessorFeature. */
308 m->fVTSupported = false;
309 m->fLongModeSupported = false;
310 m->fPAESupported = false;
311 m->fNestedPagingSupported = false;
312 m->fUnrestrictedGuestSupported = false;
313 m->fNestedHWVirtSupported = false;
314 m->fVirtVmsaveVmload = false;
315 m->fRecheckVTSupported = false;
316
317 if (ASMHasCpuId())
318 {
319 /* Note! This code is duplicated in SUPDrv.c and other places! */
320 uint32_t uMaxId, uVendorEBX, uVendorECX, uVendorEDX;
321 ASMCpuId(0, &uMaxId, &uVendorEBX, &uVendorECX, &uVendorEDX);
322 if (ASMIsValidStdRange(uMaxId))
323 {
324 /* PAE? */
325 uint32_t uDummy, fFeaturesEcx, fFeaturesEdx;
326 ASMCpuId(1, &uDummy, &uDummy, &fFeaturesEcx, &fFeaturesEdx);
327 m->fPAESupported = RT_BOOL(fFeaturesEdx & X86_CPUID_FEATURE_EDX_PAE);
328
329 /* Long Mode? */
330 uint32_t uExtMaxId, fExtFeaturesEcx, fExtFeaturesEdx;
331 ASMCpuId(0x80000000, &uExtMaxId, &uDummy, &uDummy, &uDummy);
332 ASMCpuId(0x80000001, &uDummy, &uDummy, &fExtFeaturesEcx, &fExtFeaturesEdx);
333 m->fLongModeSupported = ASMIsValidExtRange(uExtMaxId)
334 && (fExtFeaturesEdx & X86_CPUID_EXT_FEATURE_EDX_LONG_MODE);
335
336#if defined(RT_OS_DARWIN) && ARCH_BITS == 32 /* darwin.x86 has some optimizations of 64-bit on 32-bit. */
337 int f64bitCapable = 0;
338 size_t cbParameter = sizeof(f64bitCapable);
339 if (sysctlbyname("hw.cpu64bit_capable", &f64bitCapable, &cbParameter, NULL, NULL) != -1)
340 m->fLongModeSupported = f64bitCapable != 0;
341#endif
342
343 /* VT-x? */
344 if ( ASMIsIntelCpuEx(uVendorEBX, uVendorECX, uVendorEDX)
345 || ASMIsViaCentaurCpuEx(uVendorEBX, uVendorECX, uVendorEDX)
346 || ASMIsShanghaiCpuEx(uVendorEBX, uVendorECX, uVendorEDX))
347 {
348 if ( (fFeaturesEcx & X86_CPUID_FEATURE_ECX_VMX)
349 && (fFeaturesEdx & X86_CPUID_FEATURE_EDX_MSR)
350 && (fFeaturesEdx & X86_CPUID_FEATURE_EDX_FXSR)
351 )
352 {
353 const char *pszIgn;
354 int rc = SUPR3QueryVTxSupported(&pszIgn);
355 if (RT_SUCCESS(rc))
356 m->fVTSupported = true;
357 }
358 }
359 /* AMD-V */
360 else if ( ASMIsAmdCpuEx(uVendorEBX, uVendorECX, uVendorEDX)
361 || ASMIsHygonCpuEx(uVendorEBX, uVendorECX, uVendorEDX))
362 {
363 if ( (fExtFeaturesEcx & X86_CPUID_AMD_FEATURE_ECX_SVM)
364 && (fFeaturesEdx & X86_CPUID_FEATURE_EDX_MSR)
365 && (fFeaturesEdx & X86_CPUID_FEATURE_EDX_FXSR)
366 && ASMIsValidExtRange(uExtMaxId)
367 )
368 {
369 m->fVTSupported = true;
370 m->fUnrestrictedGuestSupported = true;
371
372 /* Query AMD features. */
373 if (uExtMaxId >= 0x8000000a)
374 {
375 uint32_t fSVMFeaturesEdx;
376 ASMCpuId(0x8000000a, &uDummy, &uDummy, &uDummy, &fSVMFeaturesEdx);
377 if (fSVMFeaturesEdx & X86_CPUID_SVM_FEATURE_EDX_NESTED_PAGING)
378 m->fNestedPagingSupported = true;
379 if (fSVMFeaturesEdx & X86_CPUID_SVM_FEATURE_EDX_VIRT_VMSAVE_VMLOAD)
380 m->fVirtVmsaveVmload = true;
381 }
382 }
383 }
384 }
385 }
386
387 /* Check with SUPDrv if VT-x and AMD-V are really supported (may fail). */
388 if (m->fVTSupported)
389 {
390 m->fRecheckVTSupported = true; /* Try again later when the driver is loaded; cleared by i_updateProcessorFeatures on success. */
391 i_updateProcessorFeatures();
392 }
393
394 /* Check for NEM in root paritition (hyper-V / windows). */
395 if (!m->fVTSupported && SUPR3IsNemSupportedWhenNoVtxOrAmdV())
396 {
397 m->fVTSupported = m->fNestedPagingSupported = true;
398 m->fRecheckVTSupported = false;
399 }
400
401#ifdef VBOX_WITH_3D_ACCELERATION
402 /* Test for 3D hardware acceleration support later when (if ever) need. */
403 m->f3DAccelerationSupported = -1;
404#else
405 m->f3DAccelerationSupported = false;
406#endif
407
408#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
409 /* Extract the list of configured host-only interfaces */
410 std::set<Utf8Str> aConfiguredNames;
411 SafeArray<BSTR> aGlobalExtraDataKeys;
412 hrc = aParent->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
413 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
414 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); ++i)
415 {
416 Utf8Str strKey = aGlobalExtraDataKeys[i];
417
418 if (!strKey.startsWith("HostOnly/vboxnet"))
419 continue;
420
421 size_t pos = strKey.find("/", sizeof("HostOnly/vboxnet"));
422 if (pos != Utf8Str::npos)
423 aConfiguredNames.insert(strKey.substr(sizeof("HostOnly"),
424 pos - sizeof("HostOnly")));
425 }
426
427 for (std::set<Utf8Str>::const_iterator it = aConfiguredNames.begin();
428 it != aConfiguredNames.end();
429 ++it)
430 {
431 ComPtr<IHostNetworkInterface> hif;
432 ComPtr<IProgress> progress;
433
434 int vrc = NetIfCreateHostOnlyNetworkInterface(m->pParent,
435 hif.asOutParam(),
436 progress.asOutParam(),
437 it->c_str());
438 if (RT_FAILURE(vrc))
439 LogRel(("failed to create %s, error (%Rrc)\n", it->c_str(), vrc));
440 }
441
442#endif /* defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) */
443
444 /* Confirm a successful initialization */
445 autoInitSpan.setSucceeded();
446
447 return S_OK;
448}
449
450/**
451 * Uninitializes the host object and sets the ready flag to FALSE.
452 * Called either from FinalRelease() or by the parent when it gets destroyed.
453 */
454void Host::uninit()
455{
456 LogFlowThisFunc(("\n"));
457
458 /* Enclose the state transition Ready->InUninit->NotReady */
459 AutoUninitSpan autoUninitSpan(this);
460 if (autoUninitSpan.uninitDone())
461 return;
462
463#ifdef VBOX_WITH_RESOURCE_USAGE_API
464 PerformanceCollector *aCollector = m->pParent->i_performanceCollector();
465 i_unregisterMetrics(aCollector);
466#endif /* VBOX_WITH_RESOURCE_USAGE_API */
467 /*
468 * Note that unregisterMetrics() has unregistered all metrics associated
469 * with Host including network interface ones. We can destroy network
470 * interface objects now. Don't forget the uninit call, otherwise this
471 * causes a race with crashing API clients getting their stale references
472 * cleaned up and VirtualBox shutting down.
473 */
474 while (!m->llNetIfs.empty())
475 {
476 ComObjPtr<HostNetworkInterface> &pNet = m->llNetIfs.front();
477 pNet->uninit();
478 m->llNetIfs.pop_front();
479 }
480
481 m->hostDnsMonitorProxy.uninit();
482
483 if (m->pHostUpdate)
484 {
485 m->pHostUpdate->uninit();
486 unconst(m->pHostUpdate).setNull();
487 }
488
489#ifdef VBOX_WITH_USB
490 /* wait for USB proxy service to terminate before we uninit all USB
491 * devices */
492 LogFlowThisFunc(("Stopping USB proxy service...\n"));
493 delete m->pUSBProxyService;
494 m->pUSBProxyService = NULL;
495 LogFlowThisFunc(("Done stopping USB proxy service.\n"));
496#endif
497
498 delete m->pHostPowerService;
499
500#ifdef VBOX_WITH_USB
501 /* uninit all USB device filters still referenced by clients
502 * Note! HostUSBDeviceFilter::uninit() will modify llChildren.
503 * This list should be already empty, but better be safe than sorry. */
504 while (!m->llChildren.empty())
505 {
506 ComObjPtr<HostUSBDeviceFilter> &pChild = m->llChildren.front();
507 pChild->uninit();
508 m->llChildren.pop_front();
509 }
510
511 /* No need to uninit these, as either Machine::uninit() or the above loop
512 * already covered them all. Subset of llChildren. */
513 m->llUSBDeviceFilters.clear();
514#endif
515
516 /* uninit all host DVD medium objects */
517 while (!m->llDVDDrives.empty())
518 {
519 ComObjPtr<Medium> &pMedium = m->llDVDDrives.front();
520 pMedium->uninit();
521 m->llDVDDrives.pop_front();
522 }
523 /* uninit all host floppy medium objects */
524 while (!m->llFloppyDrives.empty())
525 {
526 ComObjPtr<Medium> &pMedium = m->llFloppyDrives.front();
527 pMedium->uninit();
528 m->llFloppyDrives.pop_front();
529 }
530
531 delete m;
532 m = NULL;
533}
534
535////////////////////////////////////////////////////////////////////////////////
536//
537// IHost public methods
538//
539////////////////////////////////////////////////////////////////////////////////
540
541/**
542 * Returns a list of host DVD drives.
543 *
544 * @returns COM status code
545 * @param aDVDDrives address of result pointer
546 */
547
548HRESULT Host::getDVDDrives(std::vector<ComPtr<IMedium> > &aDVDDrives)
549{
550 AutoWriteLock treeLock(m->pParent->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
551
552 MediaList *pList;
553 HRESULT rc = i_getDrives(DeviceType_DVD, true /* fRefresh */, pList, treeLock);
554 if (FAILED(rc))
555 return rc;
556
557 aDVDDrives.resize(pList->size());
558 size_t i = 0;
559 for (MediaList::const_iterator it = pList->begin(); it != pList->end(); ++it, ++i)
560 (*it).queryInterfaceTo(aDVDDrives[i].asOutParam());
561
562 return S_OK;
563}
564
565/**
566 * Returns a list of host floppy drives.
567 *
568 * @returns COM status code
569 * @param aFloppyDrives address of result pointer
570 */
571HRESULT Host::getFloppyDrives(std::vector<ComPtr<IMedium> > &aFloppyDrives)
572{
573 AutoWriteLock treeLock(m->pParent->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
574
575 MediaList *pList;
576 HRESULT rc = i_getDrives(DeviceType_Floppy, true /* fRefresh */, pList, treeLock);
577 if (FAILED(rc))
578 return rc;
579
580 aFloppyDrives.resize(pList->size());
581 size_t i = 0;
582 for (MediaList::const_iterator it = pList->begin(); it != pList->end(); ++it, ++i)
583 (*it).queryInterfaceTo(aFloppyDrives[i].asOutParam());
584
585 return S_OK;
586}
587
588
589#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
590# define VBOX_APP_NAME L"VirtualBox"
591
592static int vboxNetWinAddComponent(std::list< ComObjPtr<HostNetworkInterface> > *pPist,
593 INetCfgComponent *pncc)
594{
595 LPWSTR lpszName;
596 GUID IfGuid;
597 HRESULT hr;
598 int rc = VERR_GENERAL_FAILURE;
599
600 hr = pncc->GetDisplayName(&lpszName);
601 Assert(hr == S_OK);
602 if (hr == S_OK)
603 {
604 Bstr name((CBSTR)lpszName);
605
606 hr = pncc->GetInstanceGuid(&IfGuid);
607 Assert(hr == S_OK);
608 if (hr == S_OK)
609 {
610 /* create a new object and add it to the list */
611 ComObjPtr<HostNetworkInterface> iface;
612 iface.createObject();
613 /* remove the curly bracket at the end */
614 if (SUCCEEDED(iface->init(name, name, Guid(IfGuid), HostNetworkInterfaceType_Bridged)))
615 {
616// iface->setVirtualBox(m->pParent);
617 pPist->push_back(iface);
618 rc = VINF_SUCCESS;
619 }
620 else
621 {
622 Assert(0);
623 }
624 }
625 CoTaskMemFree(lpszName);
626 }
627
628 return rc;
629}
630#endif /* defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT) */
631
632#if defined(RT_OS_WINDOWS)
633struct HostOnlyInfo
634{
635 HostOnlyInfo() : fDhcpEnabled(false), uIPv6PrefixLength(0) {};
636
637 Bstr bstrName;
638 bool fDhcpEnabled;
639 Bstr strIPv4Address;
640 Bstr strIPv4NetMask;
641 Bstr strIPv6Address;
642 ULONG uIPv6PrefixLength;
643};
644
645typedef std::map<Utf8Str, HostOnlyInfo*> GUID_TO_HOST_ONLY_INFO;
646
647HRESULT Host::i_updatePersistentConfigForHostOnlyAdapters(void)
648{
649 /* No need to do the sync twice */
650 if (m->fPersistentConfigUpToDate)
651 return S_OK;
652 m->fPersistentConfigUpToDate = true;
653 bool fChangesMade = false;
654
655 /* Extract the list of configured host-only interfaces */
656 GUID_TO_HOST_ONLY_INFO aSavedAdapters;
657 SafeArray<BSTR> aGlobalExtraDataKeys;
658 HRESULT hrc = m->pParent->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
659 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
660 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); ++i)
661 {
662 Utf8Str strKey = aGlobalExtraDataKeys[i];
663
664 if (strKey.startsWith("HostOnly/{"))
665 {
666 Bstr bstrValue;
667 hrc = m->pParent->GetExtraData(aGlobalExtraDataKeys[i], bstrValue.asOutParam());
668 if (hrc != S_OK)
669 continue;
670
671 Utf8Str strGuid = strKey.substr(10, 36); /* Skip "HostOnly/{" */
672 if (aSavedAdapters.find(strGuid) == aSavedAdapters.end())
673 aSavedAdapters[strGuid] = new HostOnlyInfo();
674
675 if (strKey.endsWith("}/Name"))
676 aSavedAdapters[strGuid]->bstrName = bstrValue;
677 else if (strKey.endsWith("}/IPAddress"))
678 {
679 if (bstrValue == "DHCP")
680 aSavedAdapters[strGuid]->fDhcpEnabled = true;
681 else
682 aSavedAdapters[strGuid]->strIPv4Address = bstrValue;
683 }
684 else if (strKey.endsWith("}/IPNetMask"))
685 aSavedAdapters[strGuid]->strIPv4NetMask = bstrValue;
686 else if (strKey.endsWith("}/IPV6Address"))
687 aSavedAdapters[strGuid]->strIPv6Address = bstrValue;
688 else if (strKey.endsWith("}/IPV6PrefixLen"))
689 aSavedAdapters[strGuid]->uIPv6PrefixLength = Utf8Str(bstrValue).toUInt32();
690 }
691 }
692
693 /* Go over the list of existing adapters and update configs saved in extra data */
694 std::set<Bstr> aKnownNames;
695 for (HostNetworkInterfaceList::iterator it = m->llNetIfs.begin(); it != m->llNetIfs.end(); ++it)
696 {
697 /* Get type */
698 HostNetworkInterfaceType_T t;
699 hrc = (*it)->COMGETTER(InterfaceType)(&t);
700 if (FAILED(hrc) || t != HostNetworkInterfaceType_HostOnly)
701 continue;
702 /* Get id */
703 Bstr bstrGuid;
704 hrc = (*it)->COMGETTER(Id)(bstrGuid.asOutParam());
705 if (FAILED(hrc))
706 continue;
707 /* Get name */
708 Bstr bstrName;
709 hrc = (*it)->COMGETTER(Name)(bstrName.asOutParam());
710 if (FAILED(hrc))
711 continue;
712
713 /* Remove adapter from map as it does not need any further processing */
714 aSavedAdapters.erase(Utf8Str(bstrGuid));
715 /* Add adapter name to the list of known names, so we won't attempt to create adapters with the same name */
716 aKnownNames.insert(bstrName);
717 /* Make sure our extra data contains the latest config */
718 hrc = (*it)->i_updatePersistentConfig();
719 if (hrc != S_OK)
720 break;
721 }
722
723 /* The following loop not only creates missing adapters, it destroys HostOnlyInfo objects contained in the map as well */
724 for (GUID_TO_HOST_ONLY_INFO::iterator it = aSavedAdapters.begin(); it != aSavedAdapters.end(); ++it)
725 {
726 Utf8Str strGuid = (*it).first;
727 HostOnlyInfo *pInfo = (*it).second;
728 /* We create adapters only if we haven't seen one with the same name */
729 if (aKnownNames.find(pInfo->bstrName) == aKnownNames.end())
730 {
731 /* There is no adapter with such name yet, create it */
732 ComPtr<IHostNetworkInterface> hif;
733 ComPtr<IProgress> progress;
734
735 int vrc = NetIfCreateHostOnlyNetworkInterface(m->pParent, hif.asOutParam(), progress.asOutParam(),
736 pInfo->bstrName.raw());
737 if (RT_FAILURE(vrc))
738 {
739 LogRel(("Failed to create host-only adapter (%Rrc)\n", vrc));
740 hrc = E_UNEXPECTED;
741 break;
742 }
743
744 /* Wait for the adapter to get configured completely, before we modify IP addresses. */
745 progress->WaitForCompletion(-1);
746 fChangesMade = true;
747 if (pInfo->fDhcpEnabled)
748 {
749 hrc = hif->EnableDynamicIPConfig();
750 if (FAILED(hrc))
751 LogRel(("EnableDynamicIPConfig failed with 0x%x\n", hrc));
752 }
753 else
754 {
755 hrc = hif->EnableStaticIPConfig(pInfo->strIPv4Address.raw(), pInfo->strIPv4NetMask.raw());
756 if (FAILED(hrc))
757 LogRel(("EnableStaticIpConfig failed with 0x%x\n", hrc));
758 }
759# if 0
760 /* Somehow HostNetworkInterface::EnableStaticIPConfigV6 is not implemented yet. */
761 if (SUCCEEDED(hrc))
762 {
763 hrc = hif->EnableStaticIPConfigV6(pInfo->strIPv6Address.raw(), pInfo->uIPv6PrefixLength);
764 if (FAILED(hrc))
765 LogRel(("EnableStaticIPConfigV6 failed with 0x%x\n", hrc));
766 }
767# endif
768 /* Now we have seen this name */
769 aKnownNames.insert(pInfo->bstrName);
770 /* Drop the old config as the newly created adapter has different GUID */
771 i_removePersistentConfig(strGuid);
772 }
773 delete pInfo;
774 }
775 /* Update the list again if we have created some adapters */
776 if (SUCCEEDED(hrc) && fChangesMade)
777 hrc = i_updateNetIfList();
778
779 return hrc;
780}
781#endif /* defined(RT_OS_WINDOWS) */
782
783/**
784 * Returns a list of host network interfaces.
785 *
786 * @returns COM status code
787 * @param aNetworkInterfaces address of result pointer
788 */
789HRESULT Host::getNetworkInterfaces(std::vector<ComPtr<IHostNetworkInterface> > &aNetworkInterfaces)
790{
791#if defined(RT_OS_WINDOWS) || defined(VBOX_WITH_NETFLT) /*|| defined(RT_OS_OS2)*/
792# ifdef VBOX_WITH_HOSTNETIF_API
793 HRESULT rc = i_updateNetIfList();
794 if (FAILED(rc))
795 {
796 Log(("Failed to update host network interface list with rc=%Rhrc\n", rc));
797 return rc;
798 }
799#if defined(RT_OS_WINDOWS)
800 rc = i_updatePersistentConfigForHostOnlyAdapters();
801 if (FAILED(rc))
802 {
803 LogRel(("Failed to update persistent config for host-only adapters with rc=%Rhrc\n", rc));
804 return rc;
805 }
806#endif /* defined(RT_OS_WINDOWS) */
807
808 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
809
810 aNetworkInterfaces.resize(m->llNetIfs.size());
811 size_t i = 0;
812 for (HostNetworkInterfaceList::iterator it = m->llNetIfs.begin(); it != m->llNetIfs.end(); ++it, ++i)
813 (*it).queryInterfaceTo(aNetworkInterfaces[i].asOutParam());
814
815 return S_OK;
816# else
817 std::list<ComObjPtr<HostNetworkInterface> > list;
818
819# if defined(RT_OS_DARWIN)
820 PDARWINETHERNIC pEtherNICs = DarwinGetEthernetControllers();
821 while (pEtherNICs)
822 {
823 ComObjPtr<HostNetworkInterface> IfObj;
824 IfObj.createObject();
825 if (SUCCEEDED(IfObj->init(Bstr(pEtherNICs->szName), Guid(pEtherNICs->Uuid), HostNetworkInterfaceType_Bridged)))
826 list.push_back(IfObj);
827
828 /* next, free current */
829 void *pvFree = pEtherNICs;
830 pEtherNICs = pEtherNICs->pNext;
831 RTMemFree(pvFree);
832 }
833
834# elif defined RT_OS_WINDOWS
835# ifndef VBOX_WITH_NETFLT
836 hr = E_NOTIMPL;
837# else /* # if defined VBOX_WITH_NETFLT */
838 INetCfg *pNc;
839 INetCfgComponent *pMpNcc;
840 INetCfgComponent *pTcpIpNcc;
841 LPWSTR lpszApp;
842 HRESULT hr;
843 IEnumNetCfgBindingPath *pEnumBp;
844 INetCfgBindingPath *pBp;
845 IEnumNetCfgBindingInterface *pEnumBi;
846 INetCfgBindingInterface *pBi;
847
848 /* we are using the INetCfg API for getting the list of miniports */
849 hr = VBoxNetCfgWinQueryINetCfg(FALSE,
850 VBOX_APP_NAME,
851 &pNc,
852 &lpszApp);
853 Assert(hr == S_OK);
854 if (hr == S_OK)
855 {
856# ifdef VBOX_NETFLT_ONDEMAND_BIND
857 /* for the protocol-based approach for now we just get all miniports the MS_TCPIP protocol binds to */
858 hr = pNc->FindComponent(L"MS_TCPIP", &pTcpIpNcc);
859# else
860 /* for the filter-based approach we get all miniports our filter (oracle_VBoxNetLwf)is bound to */
861 hr = pNc->FindComponent(L"oracle_VBoxNetLwf", &pTcpIpNcc);
862 if (hr != S_OK)
863 {
864 /* fall back to NDIS5 miniport lookup (sun_VBoxNetFlt) */
865 hr = pNc->FindComponent(L"sun_VBoxNetFlt", &pTcpIpNcc);
866 }
867# ifndef VBOX_WITH_HARDENING
868 if (hr != S_OK)
869 {
870 /** @todo try to install the netflt from here */
871 }
872# endif
873
874# endif
875
876 if (hr == S_OK)
877 {
878 hr = VBoxNetCfgWinGetBindingPathEnum(pTcpIpNcc, EBP_BELOW, &pEnumBp);
879 Assert(hr == S_OK);
880 if (hr == S_OK)
881 {
882 hr = VBoxNetCfgWinGetFirstBindingPath(pEnumBp, &pBp);
883 Assert(hr == S_OK || hr == S_FALSE);
884 while (hr == S_OK)
885 {
886 /* S_OK == enabled, S_FALSE == disabled */
887 if (pBp->IsEnabled() == S_OK)
888 {
889 hr = VBoxNetCfgWinGetBindingInterfaceEnum(pBp, &pEnumBi);
890 Assert(hr == S_OK);
891 if (hr == S_OK)
892 {
893 hr = VBoxNetCfgWinGetFirstBindingInterface(pEnumBi, &pBi);
894 Assert(hr == S_OK);
895 while (hr == S_OK)
896 {
897 hr = pBi->GetLowerComponent(&pMpNcc);
898 Assert(hr == S_OK);
899 if (hr == S_OK)
900 {
901 ULONG uComponentStatus;
902 hr = pMpNcc->GetDeviceStatus(&uComponentStatus);
903 Assert(hr == S_OK);
904 if (hr == S_OK)
905 {
906 if (uComponentStatus == 0)
907 {
908 vboxNetWinAddComponent(&list, pMpNcc);
909 }
910 }
911 VBoxNetCfgWinReleaseRef(pMpNcc);
912 }
913 VBoxNetCfgWinReleaseRef(pBi);
914
915 hr = VBoxNetCfgWinGetNextBindingInterface(pEnumBi, &pBi);
916 }
917 VBoxNetCfgWinReleaseRef(pEnumBi);
918 }
919 }
920 VBoxNetCfgWinReleaseRef(pBp);
921
922 hr = VBoxNetCfgWinGetNextBindingPath(pEnumBp, &pBp);
923 }
924 VBoxNetCfgWinReleaseRef(pEnumBp);
925 }
926 VBoxNetCfgWinReleaseRef(pTcpIpNcc);
927 }
928 else
929 {
930 LogRel(("failed to get the oracle_VBoxNetLwf(sun_VBoxNetFlt) component, error (0x%x)\n", hr));
931 }
932
933 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE);
934 }
935# endif /* # if defined VBOX_WITH_NETFLT */
936
937
938# elif defined RT_OS_LINUX
939 int sock = socket(AF_INET, SOCK_DGRAM, 0);
940 if (sock >= 0)
941 {
942 char pBuffer[2048];
943 struct ifconf ifConf;
944 ifConf.ifc_len = sizeof(pBuffer);
945 ifConf.ifc_buf = pBuffer;
946 if (ioctl(sock, SIOCGIFCONF, &ifConf) >= 0)
947 {
948 for (struct ifreq *pReq = ifConf.ifc_req; (char*)pReq < pBuffer + ifConf.ifc_len; pReq++)
949 {
950 if (ioctl(sock, SIOCGIFHWADDR, pReq) >= 0)
951 {
952 if (pReq->ifr_hwaddr.sa_family == ARPHRD_ETHER)
953 {
954 RTUUID uuid;
955 Assert(sizeof(uuid) <= sizeof(*pReq));
956 memcpy(&uuid, pReq, sizeof(uuid));
957
958 ComObjPtr<HostNetworkInterface> IfObj;
959 IfObj.createObject();
960 if (SUCCEEDED(IfObj->init(Bstr(pReq->ifr_name), Guid(uuid), HostNetworkInterfaceType_Bridged)))
961 list.push_back(IfObj);
962 }
963 }
964 }
965 }
966 close(sock);
967 }
968# endif /* RT_OS_LINUX */
969
970 aNetworkInterfaces.resize(list.size());
971 size_t i = 0;
972 for (std::list<ComObjPtr<HostNetworkInterface> >::const_iterator it = list.begin(); it != list.end(); ++it, ++i)
973 aNetworkInterfaces[i] = *it;
974
975 return S_OK;
976# endif
977#else
978 /* Not implemented / supported on this platform. */
979 RT_NOREF(aNetworkInterfaces);
980 ReturnComNotImplemented();
981#endif
982}
983
984HRESULT Host::getUSBDevices(std::vector<ComPtr<IHostUSBDevice> > &aUSBDevices)
985{
986#ifdef VBOX_WITH_USB
987 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
988
989 MultiResult rc = i_checkUSBProxyService();
990 if (FAILED(rc))
991 return rc;
992
993 return m->pUSBProxyService->getDeviceCollection(aUSBDevices);
994#else
995 /* Note: The GUI depends on this method returning E_NOTIMPL with no
996 * extended error info to indicate that USB is simply not available
997 * (w/o treating it as a failure), for example, as in OSE. */
998 RT_NOREF(aUSBDevices);
999 ReturnComNotImplemented();
1000#endif
1001}
1002
1003/**
1004 * This method return the list of registered name servers
1005 */
1006HRESULT Host::getNameServers(std::vector<com::Utf8Str> &aNameServers)
1007{
1008 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1009 return m->hostDnsMonitorProxy.GetNameServers(aNameServers);
1010}
1011
1012
1013/**
1014 * This method returns the domain name of the host
1015 */
1016HRESULT Host::getDomainName(com::Utf8Str &aDomainName)
1017{
1018 /* XXX: note here should be synchronization with thread polling state
1019 * changes in name resoving system on host */
1020 return m->hostDnsMonitorProxy.GetDomainName(&aDomainName);
1021}
1022
1023
1024/**
1025 * This method returns the search string.
1026 */
1027HRESULT Host::getSearchStrings(std::vector<com::Utf8Str> &aSearchStrings)
1028{
1029 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1030 return m->hostDnsMonitorProxy.GetSearchStrings(aSearchStrings);
1031}
1032
1033HRESULT Host::getUSBDeviceFilters(std::vector<ComPtr<IHostUSBDeviceFilter> > &aUSBDeviceFilters)
1034{
1035#ifdef VBOX_WITH_USB
1036 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1037
1038 MultiResult rc = i_checkUSBProxyService();
1039 if (FAILED(rc))
1040 return rc;
1041
1042 aUSBDeviceFilters.resize(m->llUSBDeviceFilters.size());
1043 size_t i = 0;
1044 for (USBDeviceFilterList::iterator it = m->llUSBDeviceFilters.begin(); it != m->llUSBDeviceFilters.end(); ++it, ++i)
1045 (*it).queryInterfaceTo(aUSBDeviceFilters[i].asOutParam());
1046
1047 return rc;
1048#else
1049 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1050 * extended error info to indicate that USB is simply not available
1051 * (w/o treating it as a failure), for example, as in OSE. */
1052 RT_NOREF(aUSBDeviceFilters);
1053 ReturnComNotImplemented();
1054#endif
1055}
1056
1057/**
1058 * Returns the number of installed logical processors
1059 *
1060 * @returns COM status code
1061 * @param aCount address of result variable
1062 */
1063
1064HRESULT Host::getProcessorCount(ULONG *aCount)
1065{
1066 // no locking required
1067
1068 *aCount = RTMpGetPresentCount();
1069 return S_OK;
1070}
1071
1072/**
1073 * Returns the number of online logical processors
1074 *
1075 * @returns COM status code
1076 * @param aCount address of result variable
1077 */
1078HRESULT Host::getProcessorOnlineCount(ULONG *aCount)
1079{
1080 // no locking required
1081
1082 *aCount = RTMpGetOnlineCount();
1083 return S_OK;
1084}
1085
1086/**
1087 * Returns the number of installed physical processor cores.
1088 *
1089 * @returns COM status code
1090 * @param aCount address of result variable
1091 */
1092HRESULT Host::getProcessorCoreCount(ULONG *aCount)
1093{
1094 // no locking required
1095
1096 *aCount = RTMpGetPresentCoreCount();
1097 return S_OK;
1098}
1099
1100/**
1101 * Returns the number of installed physical processor cores.
1102 *
1103 * @returns COM status code
1104 * @param aCount address of result variable
1105 */
1106HRESULT Host::getProcessorOnlineCoreCount(ULONG *aCount)
1107{
1108 // no locking required
1109
1110 *aCount = RTMpGetOnlineCoreCount();
1111 return S_OK;
1112}
1113
1114/**
1115 * Returns the (approximate) maximum speed of the given host CPU in MHz
1116 *
1117 * @returns COM status code
1118 * @param aCpuId id to get info for.
1119 * @param aSpeed address of result variable, speed is 0 if unknown or aCpuId
1120 * is invalid.
1121 */
1122HRESULT Host::getProcessorSpeed(ULONG aCpuId,
1123 ULONG *aSpeed)
1124{
1125 // no locking required
1126
1127 *aSpeed = RTMpGetMaxFrequency(aCpuId);
1128 return S_OK;
1129}
1130
1131/**
1132 * Returns a description string for the host CPU
1133 *
1134 * @returns COM status code
1135 * @param aCpuId id to get info for.
1136 * @param aDescription address of result variable, empty string if not known
1137 * or aCpuId is invalid.
1138 */
1139HRESULT Host::getProcessorDescription(ULONG aCpuId, com::Utf8Str &aDescription)
1140{
1141 // no locking required
1142
1143 char szCPUModel[80];
1144 szCPUModel[0] = 0;
1145 int vrc = RTMpGetDescription(aCpuId, szCPUModel, sizeof(szCPUModel));
1146 if (RT_FAILURE(vrc))
1147 return E_FAIL; /** @todo error reporting? */
1148
1149 aDescription = Utf8Str(szCPUModel);
1150
1151 return S_OK;
1152}
1153
1154/**
1155 * Updates fVTSupported, fNestedPagingSupported, fUnrestrictedGuestSupported,
1156 * fVirtVmsaveVmload and fNestedHWVirtSupported with info from SUPR3QueryVTCaps().
1157 *
1158 * This is repeated till we successfully open the support driver, in case it
1159 * is loaded after VBoxSVC starts.
1160 */
1161void Host::i_updateProcessorFeatures()
1162{
1163 /* Perhaps the driver is available now... */
1164 int rc = SUPR3InitEx(false /*fUnrestricted*/, NULL);
1165 if (RT_SUCCESS(rc))
1166 {
1167 uint32_t fVTCaps;
1168 rc = SUPR3QueryVTCaps(&fVTCaps);
1169 AssertRC(rc);
1170
1171 SUPR3Term(false);
1172
1173 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
1174 if (RT_FAILURE(rc))
1175 {
1176 LogRel(("SUPR0QueryVTCaps -> %Rrc\n", rc));
1177 fVTCaps = 0;
1178 }
1179 m->fVTSupported = (fVTCaps & (SUPVTCAPS_AMD_V | SUPVTCAPS_VT_X)) != 0;
1180 m->fNestedPagingSupported = (fVTCaps & SUPVTCAPS_NESTED_PAGING) != 0;
1181 m->fUnrestrictedGuestSupported = (fVTCaps & (SUPVTCAPS_AMD_V | SUPVTCAPS_VTX_UNRESTRICTED_GUEST)) != 0;
1182 m->fNestedHWVirtSupported = (fVTCaps & (SUPVTCAPS_AMD_V | SUPVTCAPS_NESTED_PAGING))
1183 == (SUPVTCAPS_AMD_V | SUPVTCAPS_NESTED_PAGING)
1184 || (fVTCaps & ( SUPVTCAPS_VT_X | SUPVTCAPS_NESTED_PAGING
1185 | SUPVTCAPS_VTX_UNRESTRICTED_GUEST | SUPVTCAPS_VTX_VMCS_SHADOWING))
1186 == ( SUPVTCAPS_VT_X | SUPVTCAPS_NESTED_PAGING
1187 | SUPVTCAPS_VTX_UNRESTRICTED_GUEST | SUPVTCAPS_VTX_VMCS_SHADOWING);
1188 m->fVirtVmsaveVmload = (fVTCaps & SUPVTCAPS_AMDV_VIRT_VMSAVE_VMLOAD) != 0;
1189 m->fRecheckVTSupported = false; /* No need to try again, we cached everything. */
1190 }
1191}
1192
1193/**
1194 * Returns whether a host processor feature is supported or not
1195 *
1196 * @returns COM status code
1197 * @param aFeature to query.
1198 * @param aSupported supported bool result variable
1199 */
1200HRESULT Host::getProcessorFeature(ProcessorFeature_T aFeature, BOOL *aSupported)
1201{
1202 /* Validate input. */
1203 switch (aFeature)
1204 {
1205 case ProcessorFeature_HWVirtEx:
1206 case ProcessorFeature_PAE:
1207 case ProcessorFeature_LongMode:
1208 case ProcessorFeature_NestedPaging:
1209 case ProcessorFeature_UnrestrictedGuest:
1210 case ProcessorFeature_NestedHWVirt:
1211 case ProcessorFeature_VirtVmsaveVmload:
1212 break;
1213 default:
1214 return setError(E_INVALIDARG, tr("The aFeature value %d (%#x) is out of range."), (int)aFeature, (int)aFeature);
1215 }
1216
1217 /* Do the job. */
1218 AutoCaller autoCaller(this);
1219 HRESULT hrc = autoCaller.rc();
1220 if (SUCCEEDED(hrc))
1221 {
1222 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1223
1224 if ( m->fRecheckVTSupported
1225 && ( aFeature == ProcessorFeature_HWVirtEx
1226 || aFeature == ProcessorFeature_NestedPaging
1227 || aFeature == ProcessorFeature_UnrestrictedGuest
1228 || aFeature == ProcessorFeature_NestedHWVirt
1229 || aFeature == ProcessorFeature_VirtVmsaveVmload)
1230 )
1231 {
1232 alock.release();
1233 i_updateProcessorFeatures();
1234 alock.acquire();
1235 }
1236
1237 switch (aFeature)
1238 {
1239 case ProcessorFeature_HWVirtEx:
1240 *aSupported = m->fVTSupported;
1241 break;
1242
1243 case ProcessorFeature_PAE:
1244 *aSupported = m->fPAESupported;
1245 break;
1246
1247 case ProcessorFeature_LongMode:
1248 *aSupported = m->fLongModeSupported;
1249 break;
1250
1251 case ProcessorFeature_NestedPaging:
1252 *aSupported = m->fNestedPagingSupported;
1253 break;
1254
1255 case ProcessorFeature_UnrestrictedGuest:
1256 *aSupported = m->fUnrestrictedGuestSupported;
1257 break;
1258
1259 case ProcessorFeature_NestedHWVirt:
1260 *aSupported = m->fNestedHWVirtSupported;
1261 break;
1262
1263 case ProcessorFeature_VirtVmsaveVmload:
1264 *aSupported = m->fVirtVmsaveVmload;
1265 break;
1266
1267 default:
1268 AssertFailed();
1269 }
1270 }
1271 return hrc;
1272}
1273
1274/**
1275 * Returns the specific CPUID leaf.
1276 *
1277 * @returns COM status code
1278 * @param aCpuId The CPU number. Mostly ignored.
1279 * @param aLeaf The leaf number.
1280 * @param aSubLeaf The sub-leaf number.
1281 * @param aValEAX Where to return EAX.
1282 * @param aValEBX Where to return EBX.
1283 * @param aValECX Where to return ECX.
1284 * @param aValEDX Where to return EDX.
1285 */
1286HRESULT Host::getProcessorCPUIDLeaf(ULONG aCpuId, ULONG aLeaf, ULONG aSubLeaf,
1287 ULONG *aValEAX, ULONG *aValEBX, ULONG *aValECX, ULONG *aValEDX)
1288{
1289 // no locking required
1290
1291 /* Check that the CPU is online. */
1292 /** @todo later use RTMpOnSpecific. */
1293 if (!RTMpIsCpuOnline(aCpuId))
1294 return RTMpIsCpuPresent(aCpuId)
1295 ? setError(E_FAIL, tr("CPU no.%u is not present"), aCpuId)
1296 : setError(E_FAIL, tr("CPU no.%u is not online"), aCpuId);
1297
1298 uint32_t uEAX, uEBX, uECX, uEDX;
1299 ASMCpuId_Idx_ECX(aLeaf, aSubLeaf, &uEAX, &uEBX, &uECX, &uEDX);
1300 *aValEAX = uEAX;
1301 *aValEBX = uEBX;
1302 *aValECX = uECX;
1303 *aValEDX = uEDX;
1304
1305 return S_OK;
1306}
1307
1308/**
1309 * Returns the amount of installed system memory in megabytes
1310 *
1311 * @returns COM status code
1312 * @param aSize address of result variable
1313 */
1314HRESULT Host::getMemorySize(ULONG *aSize)
1315{
1316 // no locking required
1317
1318 uint64_t cb;
1319 int rc = RTSystemQueryTotalRam(&cb);
1320 if (RT_FAILURE(rc))
1321 return E_FAIL;
1322 *aSize = (ULONG)(cb / _1M);
1323 return S_OK;
1324}
1325
1326/**
1327 * Returns the current system memory free space in megabytes
1328 *
1329 * @returns COM status code
1330 * @param aAvailable address of result variable
1331 */
1332HRESULT Host::getMemoryAvailable(ULONG *aAvailable)
1333{
1334 // no locking required
1335
1336 uint64_t cb;
1337 int rc = RTSystemQueryAvailableRam(&cb);
1338 if (RT_FAILURE(rc))
1339 return E_FAIL;
1340 *aAvailable = (ULONG)(cb / _1M);
1341 return S_OK;
1342}
1343
1344/**
1345 * Returns the name string of the host operating system
1346 *
1347 * @returns COM status code
1348 * @param aOperatingSystem result variable
1349 */
1350HRESULT Host::getOperatingSystem(com::Utf8Str &aOperatingSystem)
1351{
1352 // no locking required
1353
1354 char szOSName[80];
1355 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szOSName, sizeof(szOSName));
1356 if (RT_FAILURE(vrc))
1357 return E_FAIL; /** @todo error reporting? */
1358 aOperatingSystem = Utf8Str(szOSName);
1359 return S_OK;
1360}
1361
1362/**
1363 * Returns the version string of the host operating system
1364 *
1365 * @returns COM status code
1366 * @param aVersion address of result variable
1367 */
1368HRESULT Host::getOSVersion(com::Utf8Str &aVersion)
1369{
1370 // no locking required
1371
1372 /* Get the OS release. Reserve some buffer space for the service pack. */
1373 char szOSRelease[128];
1374 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOSRelease, sizeof(szOSRelease) - 32);
1375 if (RT_FAILURE(vrc))
1376 return E_FAIL; /** @todo error reporting? */
1377
1378 /* Append the service pack if present. */
1379 char szOSServicePack[80];
1380 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szOSServicePack, sizeof(szOSServicePack));
1381 if (RT_FAILURE(vrc))
1382 {
1383 if (vrc != VERR_NOT_SUPPORTED)
1384 return E_FAIL; /** @todo error reporting? */
1385 szOSServicePack[0] = '\0';
1386 }
1387 if (szOSServicePack[0] != '\0')
1388 {
1389 char *psz = strchr(szOSRelease, '\0');
1390 RTStrPrintf(psz, (size_t)(&szOSRelease[sizeof(szOSRelease)] - psz), "sp%s", szOSServicePack);
1391 }
1392
1393 aVersion = szOSRelease;
1394 return S_OK;
1395}
1396
1397/**
1398 * Returns the current host time in milliseconds since 1970-01-01 UTC.
1399 *
1400 * @returns COM status code
1401 * @param aUTCTime address of result variable
1402 */
1403HRESULT Host::getUTCTime(LONG64 *aUTCTime)
1404{
1405 // no locking required
1406
1407 RTTIMESPEC now;
1408 *aUTCTime = RTTimeSpecGetMilli(RTTimeNow(&now));
1409
1410 return S_OK;
1411}
1412
1413
1414HRESULT Host::getAcceleration3DAvailable(BOOL *aSupported)
1415{
1416 HRESULT hrc = S_OK;
1417 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1418 if (m->f3DAccelerationSupported != -1)
1419 *aSupported = m->f3DAccelerationSupported;
1420 else
1421 {
1422 alock.release();
1423
1424#ifdef VBOX_WITH_3D_ACCELERATION
1425 bool fSupported = VBoxOglIs3DAccelerationSupported();
1426#else
1427 bool fSupported = false; /* shoudn't get here, but just in case. */
1428#endif
1429 AutoWriteLock alock2(this COMMA_LOCKVAL_SRC_POS);
1430
1431 m->f3DAccelerationSupported = fSupported;
1432 alock2.release();
1433 *aSupported = fSupported;
1434 }
1435
1436#ifdef DEBUG_misha
1437 AssertMsgFailed(("should not be here any more!\n"));
1438#endif
1439
1440 return hrc;
1441}
1442
1443HRESULT Host::createHostOnlyNetworkInterface(ComPtr<IHostNetworkInterface> &aHostInterface,
1444 ComPtr<IProgress> &aProgress)
1445
1446{
1447#ifdef VBOX_WITH_HOSTNETIF_API
1448 /* No need to lock anything. If there ever will - watch out, the function
1449 * called below grabs the VirtualBox lock. */
1450
1451 int vrc = NetIfCreateHostOnlyNetworkInterface(m->pParent, aHostInterface.asOutParam(), aProgress.asOutParam());
1452 if (RT_SUCCESS(vrc))
1453 {
1454 if (aHostInterface.isNull())
1455 return setError(E_FAIL,
1456 tr("Unable to create a host network interface"));
1457
1458# if !defined(RT_OS_WINDOWS)
1459 Bstr tmpAddr, tmpMask, tmpName;
1460 HRESULT hrc;
1461 hrc = aHostInterface->COMGETTER(Name)(tmpName.asOutParam());
1462 ComAssertComRCRet(hrc, hrc);
1463 hrc = aHostInterface->COMGETTER(IPAddress)(tmpAddr.asOutParam());
1464 ComAssertComRCRet(hrc, hrc);
1465 hrc = aHostInterface->COMGETTER(NetworkMask)(tmpMask.asOutParam());
1466 ComAssertComRCRet(hrc, hrc);
1467 /*
1468 * We need to write the default IP address and mask to extra data now,
1469 * so the interface gets re-created after vboxnetadp.ko reload.
1470 * Note that we avoid calling EnableStaticIpConfig since it would
1471 * change the address on host's interface as well and we want to
1472 * postpone the change until VM actually starts.
1473 */
1474 hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPAddress",
1475 tmpName.raw()).raw(),
1476 tmpAddr.raw());
1477 ComAssertComRCRet(hrc, hrc);
1478
1479 hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPNetMask",
1480 tmpName.raw()).raw(),
1481 tmpMask.raw());
1482 ComAssertComRCRet(hrc, hrc);
1483# endif /* !defined(RT_OS_WINDOWS) */
1484 }
1485
1486 return S_OK;
1487#else
1488 return E_NOTIMPL;
1489#endif
1490}
1491
1492
1493#ifdef RT_OS_WINDOWS
1494HRESULT Host::i_removePersistentConfig(const Bstr &bstrGuid)
1495{
1496 HRESULT hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/{%ls}/Name", bstrGuid.raw()).raw(), NULL);
1497 if (SUCCEEDED(hrc)) hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/{%ls}/IPAddress", bstrGuid.raw()).raw(), NULL);
1498 if (SUCCEEDED(hrc)) hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/{%ls}/IPNetMask", bstrGuid.raw()).raw(), NULL);
1499 if (SUCCEEDED(hrc)) hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/{%ls}/IPV6Address", bstrGuid.raw()).raw(), NULL);
1500 if (SUCCEEDED(hrc)) hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/{%ls}/IPV6PrefixLen", bstrGuid.raw()).raw(), NULL);
1501 return hrc;
1502}
1503#endif /* RT_OS_WINDOWS */
1504
1505HRESULT Host::removeHostOnlyNetworkInterface(const com::Guid &aId,
1506 ComPtr<IProgress> &aProgress)
1507
1508{
1509#ifdef VBOX_WITH_HOSTNETIF_API
1510 /* No need to lock anything, the code below does not touch the state
1511 * of the host object. If that ever changes then check for lock order
1512 * violations with the called functions. */
1513
1514 Bstr name;
1515 HRESULT rc;
1516
1517 /* first check whether an interface with the given name already exists */
1518 {
1519 ComPtr<IHostNetworkInterface> iface;
1520 rc = findHostNetworkInterfaceById(aId, iface);
1521 if (FAILED(rc))
1522 return setError(VBOX_E_OBJECT_NOT_FOUND,
1523 tr("Host network interface with UUID {%RTuuid} does not exist"),
1524 Guid(aId).raw());
1525 rc = iface->COMGETTER(Name)(name.asOutParam());
1526 ComAssertComRCRet(rc, rc);
1527 }
1528
1529 int r = NetIfRemoveHostOnlyNetworkInterface(m->pParent, aId, aProgress.asOutParam());
1530 if (RT_SUCCESS(r))
1531 {
1532 /* Drop configuration parameters for removed interface */
1533#ifdef RT_OS_WINDOWS
1534 rc = i_removePersistentConfig(Utf8StrFmt("%RTuuid", &aId));
1535 if (FAILED(rc))
1536 LogRel(("i_removePersistentConfig(%RTuuid) failed with 0x%x\n", &aId, rc));
1537#else /* !RT_OS_WINDOWS */
1538 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPAddress", name.raw()).raw(), NULL);
1539 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPNetMask", name.raw()).raw(), NULL);
1540 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPV6Address", name.raw()).raw(), NULL);
1541 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPV6NetMask", name.raw()).raw(), NULL);
1542#endif /* !RT_OS_WINDOWS */
1543
1544 return S_OK;
1545 }
1546
1547 return r == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
1548#else
1549 return E_NOTIMPL;
1550#endif
1551}
1552
1553HRESULT Host::createUSBDeviceFilter(const com::Utf8Str &aName,
1554 ComPtr<IHostUSBDeviceFilter> &aFilter)
1555{
1556#ifdef VBOX_WITH_USB
1557
1558 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1559
1560 ComObjPtr<HostUSBDeviceFilter> filter;
1561 filter.createObject();
1562 HRESULT rc = filter->init(this, Bstr(aName).raw());
1563 ComAssertComRCRet(rc, rc);
1564 rc = filter.queryInterfaceTo(aFilter.asOutParam());
1565 AssertComRCReturn(rc, rc);
1566 return S_OK;
1567#else
1568 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1569 * extended error info to indicate that USB is simply not available
1570 * (w/o treating it as a failure), for example, as in OSE. */
1571 RT_NOREF(aName, aFilter);
1572 ReturnComNotImplemented();
1573#endif
1574}
1575
1576HRESULT Host::insertUSBDeviceFilter(ULONG aPosition,
1577 const ComPtr<IHostUSBDeviceFilter> &aFilter)
1578{
1579#ifdef VBOX_WITH_USB
1580 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1581
1582 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1583
1584 MultiResult rc = i_checkUSBProxyService();
1585 if (FAILED(rc))
1586 return rc;
1587
1588 ComObjPtr<HostUSBDeviceFilter> pFilter;
1589 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
1590 it != m->llChildren.end();
1591 ++it)
1592 {
1593 if (*it == aFilter)
1594 {
1595 pFilter = *it;
1596 break;
1597 }
1598 }
1599 if (pFilter.isNull())
1600 return setError(VBOX_E_INVALID_OBJECT_STATE,
1601 tr("The given USB device filter is not created within this VirtualBox instance"));
1602
1603 if (pFilter->mInList)
1604 return setError(E_INVALIDARG,
1605 tr("The given USB device filter is already in the list"));
1606
1607 /* iterate to the position... */
1608 USBDeviceFilterList::iterator itPos = m->llUSBDeviceFilters.begin();
1609 std::advance(itPos, aPosition);
1610 /* ...and insert */
1611 m->llUSBDeviceFilters.insert(itPos, pFilter);
1612 pFilter->mInList = true;
1613
1614 /* notify the proxy (only when the filter is active) */
1615 if ( m->pUSBProxyService->isActive()
1616 && pFilter->i_getData().mData.fActive)
1617 {
1618 ComAssertRet(pFilter->i_getId() == NULL, E_FAIL);
1619 pFilter->i_getId() = m->pUSBProxyService->insertFilter(&pFilter->i_getData().mUSBFilter);
1620 }
1621
1622 // save the global settings; for that we should hold only the VirtualBox lock
1623 alock.release();
1624 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
1625 return rc = m->pParent->i_saveSettings();
1626#else
1627
1628 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1629 * extended error info to indicate that USB is simply not available
1630 * (w/o treating it as a failure), for example, as in OSE. */
1631 RT_NOREF(aPosition, aFilter);
1632 ReturnComNotImplemented();
1633#endif
1634}
1635
1636HRESULT Host::removeUSBDeviceFilter(ULONG aPosition)
1637{
1638#ifdef VBOX_WITH_USB
1639
1640 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1641 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1642
1643 MultiResult rc = i_checkUSBProxyService();
1644 if (FAILED(rc))
1645 return rc;
1646
1647 if (!m->llUSBDeviceFilters.size())
1648 return setError(E_INVALIDARG,
1649 tr("The USB device filter list is empty"));
1650
1651 if (aPosition >= m->llUSBDeviceFilters.size())
1652 return setError(E_INVALIDARG,
1653 tr("Invalid position: %lu (must be in range [0, %lu])"),
1654 aPosition, m->llUSBDeviceFilters.size() - 1);
1655
1656 ComObjPtr<HostUSBDeviceFilter> filter;
1657 {
1658 /* iterate to the position... */
1659 USBDeviceFilterList::iterator it = m->llUSBDeviceFilters.begin();
1660 std::advance(it, aPosition);
1661 /* ...get an element from there... */
1662 filter = *it;
1663 /* ...and remove */
1664 filter->mInList = false;
1665 m->llUSBDeviceFilters.erase(it);
1666 }
1667
1668 /* notify the proxy (only when the filter is active) */
1669 if (m->pUSBProxyService->isActive() && filter->i_getData().mData.fActive)
1670 {
1671 ComAssertRet(filter->i_getId() != NULL, E_FAIL);
1672 m->pUSBProxyService->removeFilter(filter->i_getId());
1673 filter->i_getId() = NULL;
1674 }
1675
1676 // save the global settings; for that we should hold only the VirtualBox lock
1677 alock.release();
1678 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
1679 return rc = m->pParent->i_saveSettings();
1680#else
1681 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1682 * extended error info to indicate that USB is simply not available
1683 * (w/o treating it as a failure), for example, as in OSE. */
1684 RT_NOREF(aPosition);
1685 ReturnComNotImplemented();
1686#endif
1687}
1688
1689HRESULT Host::findHostDVDDrive(const com::Utf8Str &aName,
1690 ComPtr<IMedium> &aDrive)
1691{
1692 ComObjPtr<Medium> medium;
1693 HRESULT rc = i_findHostDriveByNameOrId(DeviceType_DVD, aName, medium);
1694 if (SUCCEEDED(rc))
1695 rc = medium.queryInterfaceTo(aDrive.asOutParam());
1696 else
1697 rc = setError(rc, Medium::tr("The host DVD drive named '%s' could not be found"), aName.c_str());
1698 return rc;
1699}
1700
1701HRESULT Host::findHostFloppyDrive(const com::Utf8Str &aName, ComPtr<IMedium> &aDrive)
1702{
1703 aDrive = NULL;
1704
1705 ComObjPtr<Medium>medium;
1706
1707 HRESULT rc = i_findHostDriveByNameOrId(DeviceType_Floppy, aName, medium);
1708 if (SUCCEEDED(rc))
1709 return medium.queryInterfaceTo(aDrive.asOutParam());
1710 else
1711 return setError(rc, Medium::tr("The host floppy drive named '%s' could not be found"), aName.c_str());
1712}
1713
1714HRESULT Host::findHostNetworkInterfaceByName(const com::Utf8Str &aName,
1715 ComPtr<IHostNetworkInterface> &aNetworkInterface)
1716{
1717#ifndef VBOX_WITH_HOSTNETIF_API
1718 return E_NOTIMPL;
1719#else
1720 if (!aName.length())
1721 return E_INVALIDARG;
1722
1723 HRESULT rc = i_updateNetIfList();
1724 if (FAILED(rc))
1725 {
1726 Log(("Failed to update host network interface list with rc=%Rhrc\n", rc));
1727 return rc;
1728 }
1729#if defined(RT_OS_WINDOWS)
1730 rc = i_updatePersistentConfigForHostOnlyAdapters();
1731 if (FAILED(rc))
1732 {
1733 LogRel(("Failed to update persistent config for host-only adapters with rc=%Rhrc\n", rc));
1734 return rc;
1735 }
1736#endif /* defined(RT_OS_WINDOWS) */
1737
1738 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1739
1740 ComObjPtr<HostNetworkInterface> found;
1741 for (HostNetworkInterfaceList::iterator it = m->llNetIfs.begin(); it != m->llNetIfs.end(); ++it)
1742 {
1743 Bstr n;
1744 (*it)->COMGETTER(Name)(n.asOutParam());
1745 if (n == aName)
1746 found = *it;
1747 }
1748
1749 if (!found)
1750 return setError(E_INVALIDARG,
1751 HostNetworkInterface::tr("The host network interface named '%s' could not be found"), aName.c_str());
1752
1753 return found.queryInterfaceTo(aNetworkInterface.asOutParam());
1754#endif
1755}
1756
1757HRESULT Host::findHostNetworkInterfaceById(const com::Guid &aId,
1758 ComPtr<IHostNetworkInterface> &aNetworkInterface)
1759{
1760#ifndef VBOX_WITH_HOSTNETIF_API
1761 return E_NOTIMPL;
1762#else
1763 if (!aId.isValid())
1764 return E_INVALIDARG;
1765
1766 HRESULT rc = i_updateNetIfList();
1767 if (FAILED(rc))
1768 {
1769 Log(("Failed to update host network interface list with rc=%Rhrc\n", rc));
1770 return rc;
1771 }
1772#if defined(RT_OS_WINDOWS)
1773 rc = i_updatePersistentConfigForHostOnlyAdapters();
1774 if (FAILED(rc))
1775 {
1776 LogRel(("Failed to update persistent config for host-only adapters with rc=%Rhrc\n", rc));
1777 return rc;
1778 }
1779#endif /* defined(RT_OS_WINDOWS) */
1780
1781 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1782
1783 ComObjPtr<HostNetworkInterface> found;
1784 for (HostNetworkInterfaceList::iterator it = m->llNetIfs.begin(); it != m->llNetIfs.end(); ++it)
1785 {
1786 Bstr g;
1787 (*it)->COMGETTER(Id)(g.asOutParam());
1788 if (Guid(g) == aId)
1789 found = *it;
1790 }
1791
1792 if (!found)
1793 return setError(E_INVALIDARG,
1794 HostNetworkInterface::tr("The host network interface with the given GUID could not be found"));
1795 return found.queryInterfaceTo(aNetworkInterface.asOutParam());
1796
1797#endif
1798}
1799
1800HRESULT Host::findHostNetworkInterfacesOfType(HostNetworkInterfaceType_T aType,
1801 std::vector<ComPtr<IHostNetworkInterface> > &aNetworkInterfaces)
1802{
1803#ifdef VBOX_WITH_HOSTNETIF_API
1804 HRESULT rc = i_updateNetIfList();
1805 if (FAILED(rc))
1806 {
1807 Log(("Failed to update host network interface list with rc=%Rhrc\n", rc));
1808 return rc;
1809 }
1810#if defined(RT_OS_WINDOWS)
1811 rc = i_updatePersistentConfigForHostOnlyAdapters();
1812 if (FAILED(rc))
1813 {
1814 LogRel(("Failed to update persistent config for host-only adapters with rc=%Rhrc\n", rc));
1815 return rc;
1816 }
1817#endif /* defined(RT_OS_WINDOWS) */
1818
1819 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1820
1821 HostNetworkInterfaceList resultList;
1822 for (HostNetworkInterfaceList::iterator it = m->llNetIfs.begin(); it != m->llNetIfs.end(); ++it)
1823 {
1824 HostNetworkInterfaceType_T t;
1825 HRESULT hr = (*it)->COMGETTER(InterfaceType)(&t);
1826 if (FAILED(hr))
1827 return hr;
1828
1829 if (t == aType)
1830 resultList.push_back(*it);
1831 }
1832 aNetworkInterfaces.resize(resultList.size());
1833 size_t i = 0;
1834 for (HostNetworkInterfaceList::iterator it = resultList.begin(); it != resultList.end(); ++it, ++i)
1835 {
1836 (*it).queryInterfaceTo(aNetworkInterfaces[i].asOutParam());
1837 }
1838
1839 return S_OK;
1840#else
1841 return E_NOTIMPL;
1842#endif
1843}
1844
1845HRESULT Host::findUSBDeviceByAddress(const com::Utf8Str &aName,
1846 ComPtr<IHostUSBDevice> &aDevice)
1847{
1848#ifdef VBOX_WITH_USB
1849
1850 aDevice = NULL;
1851 SafeIfaceArray<IHostUSBDevice> devsvec;
1852 HRESULT rc = COMGETTER(USBDevices)(ComSafeArrayAsOutParam(devsvec));
1853 if (FAILED(rc))
1854 return rc;
1855
1856 for (size_t i = 0; i < devsvec.size(); ++i)
1857 {
1858 Bstr address;
1859 rc = devsvec[i]->COMGETTER(Address)(address.asOutParam());
1860 if (FAILED(rc))
1861 return rc;
1862 if (address == aName)
1863 {
1864 return (ComPtr<IHostUSBDevice>(devsvec[i]).queryInterfaceTo(aDevice.asOutParam()));
1865 }
1866 }
1867
1868 return setErrorNoLog(VBOX_E_OBJECT_NOT_FOUND,
1869 tr("Could not find a USB device with address '%s'"),
1870 aName.c_str());
1871
1872#else /* !VBOX_WITH_USB */
1873 RT_NOREF(aName, aDevice);
1874 return E_NOTIMPL;
1875#endif /* !VBOX_WITH_USB */
1876}
1877HRESULT Host::findUSBDeviceById(const com::Guid &aId,
1878 ComPtr<IHostUSBDevice> &aDevice)
1879{
1880#ifdef VBOX_WITH_USB
1881 if (!aId.isValid())
1882 return E_INVALIDARG;
1883
1884 aDevice = NULL;
1885
1886 SafeIfaceArray<IHostUSBDevice> devsvec;
1887 HRESULT rc = COMGETTER(USBDevices)(ComSafeArrayAsOutParam(devsvec));
1888 if (FAILED(rc))
1889 return rc;
1890
1891 for (size_t i = 0; i < devsvec.size(); ++i)
1892 {
1893 Bstr id;
1894 rc = devsvec[i]->COMGETTER(Id)(id.asOutParam());
1895 if (FAILED(rc))
1896 return rc;
1897 if (Guid(id) == aId)
1898 {
1899 return (ComPtr<IHostUSBDevice>(devsvec[i]).queryInterfaceTo(aDevice.asOutParam()));
1900 }
1901 }
1902 return setErrorNoLog(VBOX_E_OBJECT_NOT_FOUND,
1903 tr("Could not find a USB device with uuid {%RTuuid}"),
1904 aId.raw());
1905
1906#else /* !VBOX_WITH_USB */
1907 RT_NOREF(aId, aDevice);
1908 return E_NOTIMPL;
1909#endif /* !VBOX_WITH_USB */
1910}
1911
1912HRESULT Host::generateMACAddress(com::Utf8Str &aAddress)
1913{
1914 // no locking required
1915 i_generateMACAddress(aAddress);
1916 return S_OK;
1917}
1918
1919/**
1920 * Returns a list of host video capture devices (webcams, etc).
1921 *
1922 * @returns COM status code
1923 * @param aVideoInputDevices Array of interface pointers to be filled.
1924 */
1925HRESULT Host::getVideoInputDevices(std::vector<ComPtr<IHostVideoInputDevice> > &aVideoInputDevices)
1926{
1927 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1928 HostVideoInputDeviceList list;
1929
1930 HRESULT rc = HostVideoInputDevice::queryHostDevices(m->pParent, &list);
1931 if (FAILED(rc))
1932 return rc;
1933
1934 aVideoInputDevices.resize(list.size());
1935 size_t i = 0;
1936 for (HostVideoInputDeviceList::const_iterator it = list.begin(); it != list.end(); ++it, ++i)
1937 (*it).queryInterfaceTo(aVideoInputDevices[i].asOutParam());
1938
1939 return S_OK;
1940}
1941
1942HRESULT Host::addUSBDeviceSource(const com::Utf8Str &aBackend, const com::Utf8Str &aId, const com::Utf8Str &aAddress,
1943 const std::vector<com::Utf8Str> &aPropertyNames, const std::vector<com::Utf8Str> &aPropertyValues)
1944{
1945#ifdef VBOX_WITH_USB
1946 /* The USB proxy service will do the locking. */
1947 return m->pUSBProxyService->addUSBDeviceSource(aBackend, aId, aAddress, aPropertyNames, aPropertyValues);
1948#else
1949 RT_NOREF(aBackend, aId, aAddress, aPropertyNames, aPropertyValues);
1950 ReturnComNotImplemented();
1951#endif
1952}
1953
1954HRESULT Host::removeUSBDeviceSource(const com::Utf8Str &aId)
1955{
1956#ifdef VBOX_WITH_USB
1957 /* The USB proxy service will do the locking. */
1958 return m->pUSBProxyService->removeUSBDeviceSource(aId);
1959#else
1960 RT_NOREF(aId);
1961 ReturnComNotImplemented();
1962#endif
1963}
1964
1965
1966HRESULT Host::getUpdate(ComPtr<IHostUpdate> &aUpdate)
1967{
1968 HRESULT hrc = m->pHostUpdate.queryInterfaceTo(aUpdate.asOutParam());
1969 return hrc;
1970}
1971
1972
1973// public methods only for internal purposes
1974////////////////////////////////////////////////////////////////////////////////
1975
1976HRESULT Host::i_loadSettings(const settings::Host &data)
1977{
1978 HRESULT rc = S_OK;
1979#ifdef VBOX_WITH_USB
1980 AutoCaller autoCaller(this);
1981 if (FAILED(autoCaller.rc()))
1982 return autoCaller.rc();
1983
1984 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1985
1986 for (settings::USBDeviceFiltersList::const_iterator it = data.llUSBDeviceFilters.begin();
1987 it != data.llUSBDeviceFilters.end();
1988 ++it)
1989 {
1990 const settings::USBDeviceFilter &f = *it;
1991 ComObjPtr<HostUSBDeviceFilter> pFilter;
1992 pFilter.createObject();
1993 rc = pFilter->init(this, f);
1994 if (FAILED(rc))
1995 break;
1996
1997 m->llUSBDeviceFilters.push_back(pFilter);
1998 pFilter->mInList = true;
1999
2000 /* notify the proxy (only when the filter is active) */
2001 if (pFilter->i_getData().mData.fActive)
2002 {
2003 HostUSBDeviceFilter *flt = pFilter; /* resolve ambiguity */
2004 flt->i_getId() = m->pUSBProxyService->insertFilter(&pFilter->i_getData().mUSBFilter);
2005 }
2006 }
2007
2008 rc = m->pUSBProxyService->i_loadSettings(data.llUSBDeviceSources);
2009#else
2010 RT_NOREF(data);
2011#endif /* VBOX_WITH_USB */
2012 return rc;
2013}
2014
2015HRESULT Host::i_saveSettings(settings::Host &data)
2016{
2017#ifdef VBOX_WITH_USB
2018 AutoCaller autoCaller(this);
2019 if (FAILED(autoCaller.rc()))
2020 return autoCaller.rc();
2021
2022 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2023
2024 data.llUSBDeviceFilters.clear();
2025 data.llUSBDeviceSources.clear();
2026
2027 for (USBDeviceFilterList::const_iterator it = m->llUSBDeviceFilters.begin();
2028 it != m->llUSBDeviceFilters.end();
2029 ++it)
2030 {
2031 ComObjPtr<HostUSBDeviceFilter> pFilter = *it;
2032 settings::USBDeviceFilter f;
2033 pFilter->i_saveSettings(f);
2034 data.llUSBDeviceFilters.push_back(f);
2035 }
2036
2037 return m->pUSBProxyService->i_saveSettings(data.llUSBDeviceSources);
2038#else
2039 RT_NOREF(data);
2040 return S_OK;
2041#endif /* VBOX_WITH_USB */
2042
2043}
2044
2045/**
2046 * Sets the given pointer to point to the static list of DVD or floppy
2047 * drives in the Host instance data, depending on the @a mediumType
2048 * parameter.
2049 *
2050 * This builds the list on the first call; it adds or removes host drives
2051 * that may have changed if fRefresh == true.
2052 *
2053 * The caller must hold the medium tree write lock before calling this.
2054 * To protect the list to which the caller's pointer points, the caller
2055 * must also hold that lock.
2056 *
2057 * @param mediumType Must be DeviceType_Floppy or DeviceType_DVD.
2058 * @param fRefresh Whether to refresh the host drives list even if this is not the first call.
2059 * @param pll Caller's pointer which gets set to the static list of host drives.
2060 * @param treeLock Reference to media tree lock, need to drop it temporarily.
2061 * @returns COM status code
2062 */
2063HRESULT Host::i_getDrives(DeviceType_T mediumType,
2064 bool fRefresh,
2065 MediaList *&pll,
2066 AutoWriteLock &treeLock)
2067{
2068 HRESULT rc = S_OK;
2069 Assert(m->pParent->i_getMediaTreeLockHandle().isWriteLockOnCurrentThread());
2070
2071 MediaList llNew;
2072 MediaList *pllCached;
2073 bool *pfListBuilt = NULL;
2074
2075 switch (mediumType)
2076 {
2077 case DeviceType_DVD:
2078 if (!m->fDVDDrivesListBuilt || fRefresh)
2079 {
2080 rc = i_buildDVDDrivesList(llNew);
2081 if (FAILED(rc))
2082 return rc;
2083 pfListBuilt = &m->fDVDDrivesListBuilt;
2084 }
2085 pllCached = &m->llDVDDrives;
2086 break;
2087
2088 case DeviceType_Floppy:
2089 if (!m->fFloppyDrivesListBuilt || fRefresh)
2090 {
2091 rc = i_buildFloppyDrivesList(llNew);
2092 if (FAILED(rc))
2093 return rc;
2094 pfListBuilt = &m->fFloppyDrivesListBuilt;
2095 }
2096 pllCached = &m->llFloppyDrives;
2097 break;
2098
2099 default:
2100 return E_INVALIDARG;
2101 }
2102
2103 if (pfListBuilt)
2104 {
2105 // a list was built in llNew above:
2106 if (!*pfListBuilt)
2107 {
2108 // this was the first call (instance bool is still false): then just copy the whole list and return
2109 *pllCached = llNew;
2110 // and mark the instance data as "built"
2111 *pfListBuilt = true;
2112 }
2113 else
2114 {
2115 // list was built, and this was a subsequent call: then compare the old and the new lists
2116
2117 // remove drives from the cached list which are no longer present
2118 for (MediaList::iterator itCached = pllCached->begin();
2119 itCached != pllCached->end();
2120 /*nothing */)
2121 {
2122 Medium *pCached = *itCached;
2123 const Utf8Str strLocationCached = pCached->i_getLocationFull();
2124 bool fFound = false;
2125 for (MediaList::iterator itNew = llNew.begin();
2126 itNew != llNew.end();
2127 ++itNew)
2128 {
2129 Medium *pNew = *itNew;
2130 const Utf8Str strLocationNew = pNew->i_getLocationFull();
2131 if (strLocationNew == strLocationCached)
2132 {
2133 fFound = true;
2134 break;
2135 }
2136 }
2137 if (!fFound)
2138 {
2139 pCached->uninit();
2140 itCached = pllCached->erase(itCached);
2141 }
2142 else
2143 ++itCached;
2144 }
2145
2146 // add drives to the cached list that are not on there yet
2147 for (MediaList::iterator itNew = llNew.begin();
2148 itNew != llNew.end();
2149 ++itNew)
2150 {
2151 Medium *pNew = *itNew;
2152 const Utf8Str strLocationNew = pNew->i_getLocationFull();
2153 bool fFound = false;
2154 for (MediaList::iterator itCached = pllCached->begin();
2155 itCached != pllCached->end();
2156 ++itCached)
2157 {
2158 Medium *pCached = *itCached;
2159 const Utf8Str strLocationCached = pCached->i_getLocationFull();
2160 if (strLocationNew == strLocationCached)
2161 {
2162 fFound = true;
2163 break;
2164 }
2165 }
2166
2167 if (!fFound)
2168 pllCached->push_back(pNew);
2169 }
2170 }
2171 }
2172
2173 // return cached list to caller
2174 pll = pllCached;
2175
2176 // Make sure the media tree lock is released before llNew is cleared,
2177 // as this usually triggers calls to uninit().
2178 treeLock.release();
2179
2180 llNew.clear();
2181
2182 treeLock.acquire();
2183
2184 return rc;
2185}
2186
2187/**
2188 * Goes through the list of host drives that would be returned by getDrives()
2189 * and looks for a host drive with the given UUID. If found, it sets pMedium
2190 * to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
2191 *
2192 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
2193 * @param uuid Medium UUID of host drive to look for.
2194 * @param fRefresh Whether to refresh the host drives list (see getDrives())
2195 * @param pMedium Medium object, if found...
2196 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
2197 */
2198HRESULT Host::i_findHostDriveById(DeviceType_T mediumType,
2199 const Guid &uuid,
2200 bool fRefresh,
2201 ComObjPtr<Medium> &pMedium)
2202{
2203 MediaList *pllMedia;
2204
2205 AutoWriteLock treeLock(m->pParent->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
2206 HRESULT rc = i_getDrives(mediumType, fRefresh, pllMedia, treeLock);
2207 if (SUCCEEDED(rc))
2208 {
2209 for (MediaList::iterator it = pllMedia->begin();
2210 it != pllMedia->end();
2211 ++it)
2212 {
2213 Medium *pThis = *it;
2214 AutoCaller mediumCaller(pThis);
2215 AutoReadLock mediumLock(pThis COMMA_LOCKVAL_SRC_POS);
2216 if (pThis->i_getId() == uuid)
2217 {
2218 pMedium = pThis;
2219 return S_OK;
2220 }
2221 }
2222 }
2223
2224 return VBOX_E_OBJECT_NOT_FOUND;
2225}
2226
2227/**
2228 * Goes through the list of host drives that would be returned by getDrives()
2229 * and looks for a host drive with the given name. If found, it sets pMedium
2230 * to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
2231 *
2232 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
2233 * @param strLocationFull Name (path) of host drive to look for.
2234 * @param fRefresh Whether to refresh the host drives list (see getDrives())
2235 * @param pMedium Medium object, if found
2236 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
2237 */
2238HRESULT Host::i_findHostDriveByName(DeviceType_T mediumType,
2239 const Utf8Str &strLocationFull,
2240 bool fRefresh,
2241 ComObjPtr<Medium> &pMedium)
2242{
2243 MediaList *pllMedia;
2244
2245 AutoWriteLock treeLock(m->pParent->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
2246 HRESULT rc = i_getDrives(mediumType, fRefresh, pllMedia, treeLock);
2247 if (SUCCEEDED(rc))
2248 {
2249 for (MediaList::iterator it = pllMedia->begin();
2250 it != pllMedia->end();
2251 ++it)
2252 {
2253 Medium *pThis = *it;
2254 AutoCaller mediumCaller(pThis);
2255 AutoReadLock mediumLock(pThis COMMA_LOCKVAL_SRC_POS);
2256 if (pThis->i_getLocationFull() == strLocationFull)
2257 {
2258 pMedium = pThis;
2259 return S_OK;
2260 }
2261 }
2262 }
2263
2264 return VBOX_E_OBJECT_NOT_FOUND;
2265}
2266
2267/**
2268 * Goes through the list of host drives that would be returned by getDrives()
2269 * and looks for a host drive with the given name, location or ID. If found,
2270 * it sets pMedium to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
2271 *
2272 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
2273 * @param strNameOrId Name or full location or UUID of host drive to look for.
2274 * @param pMedium Medium object, if found...
2275 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
2276 */
2277HRESULT Host::i_findHostDriveByNameOrId(DeviceType_T mediumType,
2278 const Utf8Str &strNameOrId,
2279 ComObjPtr<Medium> &pMedium)
2280{
2281 AutoWriteLock wlock(m->pParent->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
2282
2283 Guid uuid(strNameOrId);
2284 if (uuid.isValid() && !uuid.isZero())
2285 return i_findHostDriveById(mediumType, uuid, true /* fRefresh */, pMedium);
2286
2287 // string is not a syntactically valid UUID: try a name then
2288 return i_findHostDriveByName(mediumType, strNameOrId, true /* fRefresh */, pMedium);
2289}
2290
2291/**
2292 * Called from getDrives() to build the DVD drives list.
2293 * @param list Media list
2294 * @return
2295 */
2296HRESULT Host::i_buildDVDDrivesList(MediaList &list)
2297{
2298 HRESULT rc = S_OK;
2299
2300 Assert(m->pParent->i_getMediaTreeLockHandle().isWriteLockOnCurrentThread());
2301
2302 try
2303 {
2304#if defined(RT_OS_WINDOWS)
2305 int sz = GetLogicalDriveStrings(0, NULL);
2306 TCHAR *hostDrives = new TCHAR[sz+1];
2307 GetLogicalDriveStrings(sz, hostDrives);
2308 wchar_t driveName[3] = { '?', ':', '\0' };
2309 TCHAR *p = hostDrives;
2310 do
2311 {
2312 if (GetDriveType(p) == DRIVE_CDROM)
2313 {
2314 driveName[0] = *p;
2315 ComObjPtr<Medium> hostDVDDriveObj;
2316 hostDVDDriveObj.createObject();
2317 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(driveName));
2318 list.push_back(hostDVDDriveObj);
2319 }
2320 p += _tcslen(p) + 1;
2321 }
2322 while (*p);
2323 delete[] hostDrives;
2324
2325#elif defined(RT_OS_SOLARIS)
2326# ifdef VBOX_USE_LIBHAL
2327 if (!i_getDVDInfoFromHal(list))
2328# endif
2329 {
2330 i_getDVDInfoFromDevTree(list);
2331 }
2332
2333#elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
2334 if (RT_SUCCESS(m->hostDrives.updateDVDs()))
2335 for (DriveInfoList::const_iterator it = m->hostDrives.DVDBegin();
2336 SUCCEEDED(rc) && it != m->hostDrives.DVDEnd(); ++it)
2337 {
2338 ComObjPtr<Medium> hostDVDDriveObj;
2339 Utf8Str location(it->mDevice);
2340 Utf8Str description(it->mDescription);
2341 if (SUCCEEDED(rc))
2342 rc = hostDVDDriveObj.createObject();
2343 if (SUCCEEDED(rc))
2344 rc = hostDVDDriveObj->init(m->pParent, DeviceType_DVD, location, description);
2345 if (SUCCEEDED(rc))
2346 list.push_back(hostDVDDriveObj);
2347 }
2348#elif defined(RT_OS_DARWIN)
2349 PDARWINDVD cur = DarwinGetDVDDrives();
2350 while (cur)
2351 {
2352 ComObjPtr<Medium> hostDVDDriveObj;
2353 hostDVDDriveObj.createObject();
2354 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(cur->szName));
2355 list.push_back(hostDVDDriveObj);
2356
2357 /* next */
2358 void *freeMe = cur;
2359 cur = cur->pNext;
2360 RTMemFree(freeMe);
2361 }
2362#else
2363 /* PORTME */
2364#endif
2365 }
2366 catch(std::bad_alloc &)
2367 {
2368 rc = E_OUTOFMEMORY;
2369 }
2370 return rc;
2371}
2372
2373/**
2374 * Called from getDrives() to build the floppy drives list.
2375 * @param list
2376 * @return
2377 */
2378HRESULT Host::i_buildFloppyDrivesList(MediaList &list)
2379{
2380 HRESULT rc = S_OK;
2381
2382 Assert(m->pParent->i_getMediaTreeLockHandle().isWriteLockOnCurrentThread());
2383
2384 try
2385 {
2386#ifdef RT_OS_WINDOWS
2387 int sz = GetLogicalDriveStrings(0, NULL);
2388 TCHAR *hostDrives = new TCHAR[sz+1];
2389 GetLogicalDriveStrings(sz, hostDrives);
2390 wchar_t driveName[3] = { '?', ':', '\0' };
2391 TCHAR *p = hostDrives;
2392 do
2393 {
2394 if (GetDriveType(p) == DRIVE_REMOVABLE)
2395 {
2396 driveName[0] = *p;
2397 ComObjPtr<Medium> hostFloppyDriveObj;
2398 hostFloppyDriveObj.createObject();
2399 hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, Bstr(driveName));
2400 list.push_back(hostFloppyDriveObj);
2401 }
2402 p += _tcslen(p) + 1;
2403 }
2404 while (*p);
2405 delete[] hostDrives;
2406#elif defined(RT_OS_LINUX)
2407 if (RT_SUCCESS(m->hostDrives.updateFloppies()))
2408 for (DriveInfoList::const_iterator it = m->hostDrives.FloppyBegin();
2409 SUCCEEDED(rc) && it != m->hostDrives.FloppyEnd(); ++it)
2410 {
2411 ComObjPtr<Medium> hostFloppyDriveObj;
2412 Utf8Str location(it->mDevice);
2413 Utf8Str description(it->mDescription);
2414 if (SUCCEEDED(rc))
2415 rc = hostFloppyDriveObj.createObject();
2416 if (SUCCEEDED(rc))
2417 rc = hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, location, description);
2418 if (SUCCEEDED(rc))
2419 list.push_back(hostFloppyDriveObj);
2420 }
2421#else
2422 RT_NOREF(list);
2423 /* PORTME */
2424#endif
2425 }
2426 catch(std::bad_alloc &)
2427 {
2428 rc = E_OUTOFMEMORY;
2429 }
2430
2431 return rc;
2432}
2433
2434#ifdef VBOX_WITH_USB
2435USBProxyService* Host::i_usbProxyService()
2436{
2437 return m->pUSBProxyService;
2438}
2439
2440HRESULT Host::i_addChild(HostUSBDeviceFilter *pChild)
2441{
2442 AutoCaller autoCaller(this);
2443 if (FAILED(autoCaller.rc()))
2444 return autoCaller.rc();
2445
2446 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2447
2448 m->llChildren.push_back(pChild);
2449
2450 return S_OK;
2451}
2452
2453HRESULT Host::i_removeChild(HostUSBDeviceFilter *pChild)
2454{
2455 AutoCaller autoCaller(this);
2456 if (FAILED(autoCaller.rc()))
2457 return autoCaller.rc();
2458
2459 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2460
2461 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
2462 it != m->llChildren.end();
2463 ++it)
2464 {
2465 if (*it == pChild)
2466 {
2467 m->llChildren.erase(it);
2468 break;
2469 }
2470 }
2471
2472 return S_OK;
2473}
2474
2475VirtualBox* Host::i_parent()
2476{
2477 return m->pParent;
2478}
2479
2480/**
2481 * Called by setter methods of all USB device filters.
2482 */
2483HRESULT Host::i_onUSBDeviceFilterChange(HostUSBDeviceFilter *aFilter,
2484 BOOL aActiveChanged /* = FALSE */)
2485{
2486 AutoCaller autoCaller(this);
2487 if (FAILED(autoCaller.rc()))
2488 return autoCaller.rc();
2489
2490 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2491
2492 if (aFilter->mInList)
2493 {
2494 if (aActiveChanged)
2495 {
2496 // insert/remove the filter from the proxy
2497 if (aFilter->i_getData().mData.fActive)
2498 {
2499 ComAssertRet(aFilter->i_getId() == NULL, E_FAIL);
2500 aFilter->i_getId() = m->pUSBProxyService->insertFilter(&aFilter->i_getData().mUSBFilter);
2501 }
2502 else
2503 {
2504 ComAssertRet(aFilter->i_getId() != NULL, E_FAIL);
2505 m->pUSBProxyService->removeFilter(aFilter->i_getId());
2506 aFilter->i_getId() = NULL;
2507 }
2508 }
2509 else
2510 {
2511 if (aFilter->i_getData().mData.fActive)
2512 {
2513 // update the filter in the proxy
2514 ComAssertRet(aFilter->i_getId() != NULL, E_FAIL);
2515 m->pUSBProxyService->removeFilter(aFilter->i_getId());
2516 aFilter->i_getId() = m->pUSBProxyService->insertFilter(&aFilter->i_getData().mUSBFilter);
2517 }
2518 }
2519
2520 // save the global settings... yeah, on every single filter property change
2521 // for that we should hold only the VirtualBox lock
2522 alock.release();
2523 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
2524 return m->pParent->i_saveSettings();
2525 }
2526
2527 return S_OK;
2528}
2529
2530
2531/**
2532 * Interface for obtaining a copy of the USBDeviceFilterList,
2533 * used by the USBProxyService.
2534 *
2535 * @param aGlobalFilters Where to put the global filter list copy.
2536 * @param aMachines Where to put the machine vector.
2537 */
2538void Host::i_getUSBFilters(Host::USBDeviceFilterList *aGlobalFilters)
2539{
2540 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2541
2542 *aGlobalFilters = m->llUSBDeviceFilters;
2543}
2544
2545#endif /* VBOX_WITH_USB */
2546
2547// private methods
2548////////////////////////////////////////////////////////////////////////////////
2549
2550#if defined(RT_OS_SOLARIS) && defined(VBOX_USE_LIBHAL)
2551
2552/**
2553 * Helper function to get the slice number from a device path
2554 *
2555 * @param pszDevLinkPath Pointer to a device path (/dev/(r)dsk/c7d1t0d0s3 etc.)
2556 * @returns Pointer to the slice portion of the given path.
2557 */
2558static char *solarisGetSliceFromPath(const char *pszDevLinkPath)
2559{
2560 char *pszFound = NULL;
2561 char *pszSlice = strrchr(pszDevLinkPath, 's');
2562 char *pszDisk = strrchr(pszDevLinkPath, 'd');
2563 if (pszSlice && pszSlice > pszDisk)
2564 pszFound = pszSlice;
2565 else
2566 pszFound = pszDisk;
2567
2568 if (pszFound && RT_C_IS_DIGIT(pszFound[1]))
2569 return pszFound;
2570
2571 return NULL;
2572}
2573
2574/**
2575 * Walk device links and returns an allocated path for the first one in the snapshot.
2576 *
2577 * @param DevLink Handle to the device link being walked.
2578 * @param pvArg Opaque data containing the pointer to the path.
2579 * @returns Pointer to an allocated device path string.
2580 */
2581static int solarisWalkDevLink(di_devlink_t DevLink, void *pvArg)
2582{
2583 char **ppszPath = (char **)pvArg;
2584 *ppszPath = strdup(di_devlink_path(DevLink));
2585 return DI_WALK_TERMINATE;
2586}
2587
2588/**
2589 * Walk all devices in the system and enumerate CD/DVD drives.
2590 * @param Node Handle to the current node.
2591 * @param pvArg Opaque data (holds list pointer).
2592 * @returns Solaris specific code whether to continue walking or not.
2593 */
2594static int solarisWalkDeviceNodeForDVD(di_node_t Node, void *pvArg)
2595{
2596 PSOLARISDVD *ppDrives = (PSOLARISDVD *)pvArg;
2597
2598 /*
2599 * Check for "removable-media" or "hotpluggable" instead of "SCSI" so that we also include USB CD-ROMs.
2600 * As unfortunately the Solaris drivers only export these common properties.
2601 */
2602 int *pInt = NULL;
2603 if ( di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "removable-media", &pInt) >= 0
2604 || di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "hotpluggable", &pInt) >= 0)
2605 {
2606 if (di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "inquiry-device-type", &pInt) > 0
2607 && ( *pInt == DTYPE_RODIRECT /* CDROM */
2608 || *pInt == DTYPE_OPTICAL)) /* Optical Drive */
2609 {
2610 char *pszProduct = NULL;
2611 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-product-id", &pszProduct) > 0)
2612 {
2613 char *pszVendor = NULL;
2614 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-vendor-id", &pszVendor) > 0)
2615 {
2616 /*
2617 * Found a DVD drive, we need to scan the minor nodes to find the correct
2618 * slice that represents the whole drive. "s2" is always the whole drive for CD/DVDs.
2619 */
2620 int Major = di_driver_major(Node);
2621 di_minor_t Minor = DI_MINOR_NIL;
2622 di_devlink_handle_t DevLink = di_devlink_init(NULL /* name */, 0 /* flags */);
2623 if (DevLink)
2624 {
2625 while ((Minor = di_minor_next(Node, Minor)) != DI_MINOR_NIL)
2626 {
2627 dev_t Dev = di_minor_devt(Minor);
2628 if ( Major != (int)major(Dev)
2629 || di_minor_spectype(Minor) == S_IFBLK
2630 || di_minor_type(Minor) != DDM_MINOR)
2631 {
2632 continue;
2633 }
2634
2635 char *pszMinorPath = di_devfs_minor_path(Minor);
2636 if (!pszMinorPath)
2637 continue;
2638
2639 char *pszDevLinkPath = NULL;
2640 di_devlink_walk(DevLink, NULL, pszMinorPath, DI_PRIMARY_LINK, &pszDevLinkPath, solarisWalkDevLink);
2641 di_devfs_path_free(pszMinorPath);
2642
2643 if (pszDevLinkPath)
2644 {
2645 char *pszSlice = solarisGetSliceFromPath(pszDevLinkPath);
2646 if ( pszSlice && !strcmp(pszSlice, "s2")
2647 && !strncmp(pszDevLinkPath, RT_STR_TUPLE("/dev/rdsk"))) /* We want only raw disks */
2648 {
2649 /*
2650 * We've got a fully qualified DVD drive. Add it to the list.
2651 */
2652 PSOLARISDVD pDrive = (PSOLARISDVD)RTMemAllocZ(sizeof(SOLARISDVD));
2653 if (RT_LIKELY(pDrive))
2654 {
2655 RTStrPrintf(pDrive->szDescription, sizeof(pDrive->szDescription),
2656 "%s %s", pszVendor, pszProduct);
2657 RTStrCopy(pDrive->szRawDiskPath, sizeof(pDrive->szRawDiskPath), pszDevLinkPath);
2658 if (*ppDrives)
2659 pDrive->pNext = *ppDrives;
2660 *ppDrives = pDrive;
2661
2662 /* We're not interested in any of the other slices, stop minor nodes traversal. */
2663 free(pszDevLinkPath);
2664 break;
2665 }
2666 }
2667 free(pszDevLinkPath);
2668 }
2669 }
2670 di_devlink_fini(&DevLink);
2671 }
2672 }
2673 }
2674 }
2675 }
2676 return DI_WALK_CONTINUE;
2677}
2678
2679/**
2680 * Solaris specific function to enumerate CD/DVD drives via the device tree.
2681 * Works on Solaris 10 as well as OpenSolaris without depending on libhal.
2682 */
2683void Host::i_getDVDInfoFromDevTree(std::list<ComObjPtr<Medium> > &list)
2684{
2685 PSOLARISDVD pDrives = NULL;
2686 di_node_t RootNode = di_init("/", DINFOCPYALL);
2687 if (RootNode != DI_NODE_NIL)
2688 di_walk_node(RootNode, DI_WALK_CLDFIRST, &pDrives, solarisWalkDeviceNodeForDVD);
2689
2690 di_fini(RootNode);
2691
2692 while (pDrives)
2693 {
2694 ComObjPtr<Medium> hostDVDDriveObj;
2695 hostDVDDriveObj.createObject();
2696 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(pDrives->szRawDiskPath), Bstr(pDrives->szDescription));
2697 list.push_back(hostDVDDriveObj);
2698
2699 void *pvDrive = pDrives;
2700 pDrives = pDrives->pNext;
2701 RTMemFree(pvDrive);
2702 }
2703}
2704
2705/* Solaris hosts, loading libhal at runtime */
2706
2707/**
2708 * Helper function to query the hal subsystem for information about DVD drives attached to the
2709 * system.
2710 *
2711 * @returns true if information was successfully obtained, false otherwise
2712 * @retval list drives found will be attached to this list
2713 */
2714bool Host::i_getDVDInfoFromHal(std::list<ComObjPtr<Medium> > &list)
2715{
2716 bool halSuccess = false;
2717 DBusError dbusError;
2718 if (!gLibHalCheckPresence())
2719 return false;
2720 gDBusErrorInit(&dbusError);
2721 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
2722 if (dbusConnection != 0)
2723 {
2724 LibHalContext *halContext = gLibHalCtxNew();
2725 if (halContext != 0)
2726 {
2727 if (gLibHalCtxSetDBusConnection(halContext, dbusConnection))
2728 {
2729 if (gLibHalCtxInit(halContext, &dbusError))
2730 {
2731 int numDevices;
2732 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
2733 "storage.drive_type", "cdrom",
2734 &numDevices, &dbusError);
2735 if (halDevices != 0)
2736 {
2737 /* Hal is installed and working, so if no devices are reported, assume
2738 that there are none. */
2739 halSuccess = true;
2740 for (int i = 0; i < numDevices; i++)
2741 {
2742 char *devNode = gLibHalDeviceGetPropertyString(halContext,
2743 halDevices[i], "block.device", &dbusError);
2744#ifdef RT_OS_SOLARIS
2745 /* The CD/DVD ioctls work only for raw device nodes. */
2746 char *tmp = getfullrawname(devNode);
2747 gLibHalFreeString(devNode);
2748 devNode = tmp;
2749#endif
2750
2751 if (devNode != 0)
2752 {
2753// if (validateDevice(devNode, true))
2754// {
2755 Utf8Str description;
2756 char *vendor, *product;
2757 /* We do not check the error here, as this field may
2758 not even exist. */
2759 vendor = gLibHalDeviceGetPropertyString(halContext,
2760 halDevices[i], "info.vendor", 0);
2761 product = gLibHalDeviceGetPropertyString(halContext,
2762 halDevices[i], "info.product", &dbusError);
2763 if ((product != 0 && product[0] != 0))
2764 {
2765 if ((vendor != 0) && (vendor[0] != 0))
2766 {
2767 description = Utf8StrFmt("%s %s",
2768 vendor, product);
2769 }
2770 else
2771 {
2772 description = product;
2773 }
2774 ComObjPtr<Medium> hostDVDDriveObj;
2775 hostDVDDriveObj.createObject();
2776 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
2777 Bstr(devNode), Bstr(description));
2778 list.push_back(hostDVDDriveObj);
2779 }
2780 else
2781 {
2782 if (product == 0)
2783 {
2784 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
2785 halDevices[i], dbusError.name, dbusError.message));
2786 gDBusErrorFree(&dbusError);
2787 }
2788 ComObjPtr<Medium> hostDVDDriveObj;
2789 hostDVDDriveObj.createObject();
2790 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
2791 Bstr(devNode));
2792 list.push_back(hostDVDDriveObj);
2793 }
2794 if (vendor != 0)
2795 {
2796 gLibHalFreeString(vendor);
2797 }
2798 if (product != 0)
2799 {
2800 gLibHalFreeString(product);
2801 }
2802// }
2803// else
2804// {
2805// LogRel(("Host::COMGETTER(DVDDrives): failed to validate the block device %s as a DVD drive\n"));
2806// }
2807#ifndef RT_OS_SOLARIS
2808 gLibHalFreeString(devNode);
2809#else
2810 free(devNode);
2811#endif
2812 }
2813 else
2814 {
2815 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
2816 halDevices[i], dbusError.name, dbusError.message));
2817 gDBusErrorFree(&dbusError);
2818 }
2819 }
2820 gLibHalFreeStringArray(halDevices);
2821 }
2822 else
2823 {
2824 LogRel(("Host::COMGETTER(DVDDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2825 gDBusErrorFree(&dbusError);
2826 }
2827 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
2828 {
2829 LogRel(("Host::COMGETTER(DVDDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n",
2830 dbusError.name, dbusError.message));
2831 gDBusErrorFree(&dbusError);
2832 }
2833 }
2834 else
2835 {
2836 LogRel(("Host::COMGETTER(DVDDrives): failed to initialise libhal context. dbus error: %s (%s)\n",
2837 dbusError.name, dbusError.message));
2838 gDBusErrorFree(&dbusError);
2839 }
2840 gLibHalCtxFree(halContext);
2841 }
2842 else
2843 {
2844 LogRel(("Host::COMGETTER(DVDDrives): failed to set libhal connection to dbus.\n"));
2845 }
2846 }
2847 else
2848 {
2849 LogRel(("Host::COMGETTER(DVDDrives): failed to get a libhal context - out of memory?\n"));
2850 }
2851 gDBusConnectionUnref(dbusConnection);
2852 }
2853 else
2854 {
2855 LogRel(("Host::COMGETTER(DVDDrives): failed to connect to dbus. dbus error: %s (%s)\n",
2856 dbusError.name, dbusError.message));
2857 gDBusErrorFree(&dbusError);
2858 }
2859 return halSuccess;
2860}
2861
2862
2863/**
2864 * Helper function to query the hal subsystem for information about floppy drives attached to the
2865 * system.
2866 *
2867 * @returns true if information was successfully obtained, false otherwise
2868 * @retval list drives found will be attached to this list
2869 */
2870bool Host::i_getFloppyInfoFromHal(std::list< ComObjPtr<Medium> > &list)
2871{
2872 bool halSuccess = false;
2873 DBusError dbusError;
2874 if (!gLibHalCheckPresence())
2875 return false;
2876 gDBusErrorInit(&dbusError);
2877 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
2878 if (dbusConnection != 0)
2879 {
2880 LibHalContext *halContext = gLibHalCtxNew();
2881 if (halContext != 0)
2882 {
2883 if (gLibHalCtxSetDBusConnection(halContext, dbusConnection))
2884 {
2885 if (gLibHalCtxInit(halContext, &dbusError))
2886 {
2887 int numDevices;
2888 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
2889 "storage.drive_type", "floppy",
2890 &numDevices, &dbusError);
2891 if (halDevices != 0)
2892 {
2893 /* Hal is installed and working, so if no devices are reported, assume
2894 that there are none. */
2895 halSuccess = true;
2896 for (int i = 0; i < numDevices; i++)
2897 {
2898 char *driveType = gLibHalDeviceGetPropertyString(halContext,
2899 halDevices[i], "storage.drive_type", 0);
2900 if (driveType != 0)
2901 {
2902 if (strcmp(driveType, "floppy") != 0)
2903 {
2904 gLibHalFreeString(driveType);
2905 continue;
2906 }
2907 gLibHalFreeString(driveType);
2908 }
2909 else
2910 {
2911 /* An error occurred. The attribute "storage.drive_type"
2912 probably didn't exist. */
2913 continue;
2914 }
2915 char *devNode = gLibHalDeviceGetPropertyString(halContext,
2916 halDevices[i], "block.device", &dbusError);
2917 if (devNode != 0)
2918 {
2919// if (validateDevice(devNode, false))
2920// {
2921 Utf8Str description;
2922 char *vendor, *product;
2923 /* We do not check the error here, as this field may
2924 not even exist. */
2925 vendor = gLibHalDeviceGetPropertyString(halContext,
2926 halDevices[i], "info.vendor", 0);
2927 product = gLibHalDeviceGetPropertyString(halContext,
2928 halDevices[i], "info.product", &dbusError);
2929 if ((product != 0) && (product[0] != 0))
2930 {
2931 if ((vendor != 0) && (vendor[0] != 0))
2932 {
2933 description = Utf8StrFmt("%s %s",
2934 vendor, product);
2935 }
2936 else
2937 {
2938 description = product;
2939 }
2940 ComObjPtr<Medium> hostFloppyDrive;
2941 hostFloppyDrive.createObject();
2942 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
2943 Bstr(devNode), Bstr(description));
2944 list.push_back(hostFloppyDrive);
2945 }
2946 else
2947 {
2948 if (product == 0)
2949 {
2950 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
2951 halDevices[i], dbusError.name, dbusError.message));
2952 gDBusErrorFree(&dbusError);
2953 }
2954 ComObjPtr<Medium> hostFloppyDrive;
2955 hostFloppyDrive.createObject();
2956 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
2957 Bstr(devNode));
2958 list.push_back(hostFloppyDrive);
2959 }
2960 if (vendor != 0)
2961 {
2962 gLibHalFreeString(vendor);
2963 }
2964 if (product != 0)
2965 {
2966 gLibHalFreeString(product);
2967 }
2968// }
2969// else
2970// {
2971// LogRel(("Host::COMGETTER(FloppyDrives): failed to validate the block device %s as a floppy drive\n"));
2972// }
2973 gLibHalFreeString(devNode);
2974 }
2975 else
2976 {
2977 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
2978 halDevices[i], dbusError.name, dbusError.message));
2979 gDBusErrorFree(&dbusError);
2980 }
2981 }
2982 gLibHalFreeStringArray(halDevices);
2983 }
2984 else
2985 {
2986 LogRel(("Host::COMGETTER(FloppyDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2987 gDBusErrorFree(&dbusError);
2988 }
2989 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
2990 {
2991 LogRel(("Host::COMGETTER(FloppyDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n",
2992 dbusError.name, dbusError.message));
2993 gDBusErrorFree(&dbusError);
2994 }
2995 }
2996 else
2997 {
2998 LogRel(("Host::COMGETTER(FloppyDrives): failed to initialise libhal context. dbus error: %s (%s)\n",
2999 dbusError.name, dbusError.message));
3000 gDBusErrorFree(&dbusError);
3001 }
3002 gLibHalCtxFree(halContext);
3003 }
3004 else
3005 {
3006 LogRel(("Host::COMGETTER(FloppyDrives): failed to set libhal connection to dbus.\n"));
3007 }
3008 }
3009 else
3010 {
3011 LogRel(("Host::COMGETTER(FloppyDrives): failed to get a libhal context - out of memory?\n"));
3012 }
3013 gDBusConnectionUnref(dbusConnection);
3014 }
3015 else
3016 {
3017 LogRel(("Host::COMGETTER(FloppyDrives): failed to connect to dbus. dbus error: %s (%s)\n",
3018 dbusError.name, dbusError.message));
3019 gDBusErrorFree(&dbusError);
3020 }
3021 return halSuccess;
3022}
3023#endif /* RT_OS_SOLARIS and VBOX_USE_HAL */
3024
3025/** @todo get rid of dead code below - RT_OS_SOLARIS and RT_OS_LINUX are never both set */
3026#if defined(RT_OS_SOLARIS)
3027
3028/**
3029 * Helper function to parse the given mount file and add found entries
3030 */
3031void Host::i_parseMountTable(char *mountTable, std::list< ComObjPtr<Medium> > &list)
3032{
3033#ifdef RT_OS_LINUX
3034 FILE *mtab = setmntent(mountTable, "r");
3035 if (mtab)
3036 {
3037 struct mntent *mntent;
3038 char *mnt_type;
3039 char *mnt_dev;
3040 char *tmp;
3041 while ((mntent = getmntent(mtab)))
3042 {
3043 mnt_type = (char*)malloc(strlen(mntent->mnt_type) + 1);
3044 mnt_dev = (char*)malloc(strlen(mntent->mnt_fsname) + 1);
3045 strcpy(mnt_type, mntent->mnt_type);
3046 strcpy(mnt_dev, mntent->mnt_fsname);
3047 // supermount fs case
3048 if (strcmp(mnt_type, "supermount") == 0)
3049 {
3050 tmp = strstr(mntent->mnt_opts, "fs=");
3051 if (tmp)
3052 {
3053 free(mnt_type);
3054 mnt_type = strdup(tmp + strlen("fs="));
3055 if (mnt_type)
3056 {
3057 tmp = strchr(mnt_type, ',');
3058 if (tmp)
3059 *tmp = '\0';
3060 }
3061 }
3062 tmp = strstr(mntent->mnt_opts, "dev=");
3063 if (tmp)
3064 {
3065 free(mnt_dev);
3066 mnt_dev = strdup(tmp + strlen("dev="));
3067 if (mnt_dev)
3068 {
3069 tmp = strchr(mnt_dev, ',');
3070 if (tmp)
3071 *tmp = '\0';
3072 }
3073 }
3074 }
3075 // use strstr here to cover things fs types like "udf,iso9660"
3076 if (strstr(mnt_type, "iso9660") == 0)
3077 {
3078 /** @todo check whether we've already got the drive in our list! */
3079 if (i_validateDevice(mnt_dev, true))
3080 {
3081 ComObjPtr<Medium> hostDVDDriveObj;
3082 hostDVDDriveObj.createObject();
3083 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(mnt_dev));
3084 list.push_back (hostDVDDriveObj);
3085 }
3086 }
3087 free(mnt_dev);
3088 free(mnt_type);
3089 }
3090 endmntent(mtab);
3091 }
3092#else // RT_OS_SOLARIS
3093 FILE *mntFile = fopen(mountTable, "r");
3094 if (mntFile)
3095 {
3096 struct mnttab mntTab;
3097 while (getmntent(mntFile, &mntTab) == 0)
3098 {
3099 const char *mountName = mntTab.mnt_special;
3100 const char *mountPoint = mntTab.mnt_mountp;
3101 const char *mountFSType = mntTab.mnt_fstype;
3102 if (mountName && mountPoint && mountFSType)
3103 {
3104 // skip devices we are not interested in
3105 if ((*mountName && mountName[0] == '/') && // skip 'fake' devices (like -hosts,
3106 // proc, fd, swap)
3107 (*mountFSType && (strncmp(mountFSType, RT_STR_TUPLE("devfs")) != 0 && // skip devfs
3108 // (i.e. /devices)
3109 strncmp(mountFSType, RT_STR_TUPLE("dev")) != 0 && // skip dev (i.e. /dev)
3110 strncmp(mountFSType, RT_STR_TUPLE("lofs")) != 0))) // skip loop-back file-system (lofs)
3111 {
3112 char *rawDevName = getfullrawname((char *)mountName);
3113 if (i_validateDevice(rawDevName, true))
3114 {
3115 ComObjPtr<Medium> hostDVDDriveObj;
3116 hostDVDDriveObj.createObject();
3117 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(rawDevName));
3118 list.push_back(hostDVDDriveObj);
3119 }
3120 free(rawDevName);
3121 }
3122 }
3123 }
3124
3125 fclose(mntFile);
3126 }
3127#endif
3128}
3129
3130/**
3131 * Helper function to check whether the given device node is a valid drive
3132 */
3133bool Host::i_validateDevice(const char *deviceNode, bool isCDROM)
3134{
3135 struct stat statInfo;
3136 bool retValue = false;
3137
3138 // sanity check
3139 if (!deviceNode)
3140 {
3141 return false;
3142 }
3143
3144 // first a simple stat() call
3145 if (stat(deviceNode, &statInfo) < 0)
3146 {
3147 return false;
3148 }
3149 else
3150 {
3151 if (isCDROM)
3152 {
3153 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
3154 {
3155 int fileHandle;
3156 // now try to open the device
3157 fileHandle = open(deviceNode, O_RDONLY | O_NONBLOCK, 0);
3158 if (fileHandle >= 0)
3159 {
3160 cdrom_subchnl cdChannelInfo;
3161 cdChannelInfo.cdsc_format = CDROM_MSF;
3162 // this call will finally reveal the whole truth
3163#ifdef RT_OS_LINUX
3164 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
3165 (errno == EIO) || (errno == ENOENT) ||
3166 (errno == EINVAL) || (errno == ENOMEDIUM))
3167#else
3168 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
3169 (errno == EIO) || (errno == ENOENT) ||
3170 (errno == EINVAL))
3171#endif
3172 {
3173 retValue = true;
3174 }
3175 close(fileHandle);
3176 }
3177 }
3178 } else
3179 {
3180 // floppy case
3181 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
3182 {
3183 /// @todo do some more testing, maybe a nice IOCTL!
3184 retValue = true;
3185 }
3186 }
3187 }
3188 return retValue;
3189}
3190#endif // RT_OS_SOLARIS
3191
3192#ifdef VBOX_WITH_USB
3193/**
3194 * Checks for the presence and status of the USB Proxy Service.
3195 * Returns S_OK when the Proxy is present and OK, VBOX_E_HOST_ERROR (as a
3196 * warning) if the proxy service is not available due to the way the host is
3197 * configured (at present, that means that usbfs and hal/DBus are not
3198 * available on a Linux host) or E_FAIL and a corresponding error message
3199 * otherwise. Intended to be used by methods that rely on the Proxy Service
3200 * availability.
3201 *
3202 * @note This method may return a warning result code. It is recommended to use
3203 * MultiError to store the return value.
3204 *
3205 * @note Locks this object for reading.
3206 */
3207HRESULT Host::i_checkUSBProxyService()
3208{
3209 AutoCaller autoCaller(this);
3210 if (FAILED(autoCaller.rc()))
3211 return autoCaller.rc();
3212
3213 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
3214
3215 AssertReturn(m->pUSBProxyService, E_FAIL);
3216 if (!m->pUSBProxyService->isActive())
3217 {
3218 /* disable the USB controller completely to avoid assertions if the
3219 * USB proxy service could not start. */
3220
3221 switch (m->pUSBProxyService->getLastError())
3222 {
3223 case VERR_FILE_NOT_FOUND: /** @todo what does this mean? */
3224 return setWarning(E_FAIL,
3225 tr("Could not load the Host USB Proxy Service (VERR_FILE_NOT_FOUND). The service might not be installed on the host computer"));
3226 case VERR_VUSB_USB_DEVICE_PERMISSION:
3227 return setWarning(E_FAIL,
3228 tr("VirtualBox is not currently allowed to access USB devices. You can change this by adding your user to the 'vboxusers' group. Please see the user manual for a more detailed explanation"));
3229 case VERR_VUSB_USBFS_PERMISSION:
3230 return setWarning(E_FAIL,
3231 tr("VirtualBox is not currently allowed to access USB devices. You can change this by allowing your user to access the 'usbfs' folder and files. Please see the user manual for a more detailed explanation"));
3232 case VINF_SUCCESS:
3233 return setWarning(E_FAIL,
3234 tr("The USB Proxy Service has not yet been ported to this host"));
3235 default:
3236 return setWarning(E_FAIL, "%s: %Rrc",
3237 tr("Could not load the Host USB Proxy service"),
3238 m->pUSBProxyService->getLastError());
3239 }
3240 }
3241
3242 return S_OK;
3243}
3244#endif /* VBOX_WITH_USB */
3245
3246HRESULT Host::i_updateNetIfList()
3247{
3248#ifdef VBOX_WITH_HOSTNETIF_API
3249 AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
3250
3251 /** @todo r=klaus it would save lots of clock cycles if for concurrent
3252 * threads executing this code we'd only do one interface enumeration
3253 * and update, and let the other threads use the result as is. However
3254 * if there's a constant hammering of this method, we don't want this
3255 * to cause update starvation. */
3256 HostNetworkInterfaceList list;
3257 int rc = NetIfList(list);
3258 if (rc)
3259 {
3260 Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
3261 return E_FAIL;
3262 }
3263
3264 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
3265
3266 AssertReturn(m->pParent, E_FAIL);
3267 /* Make a copy as the original may be partially destroyed later. */
3268 HostNetworkInterfaceList listCopy(list);
3269 HostNetworkInterfaceList::iterator itOld, itNew;
3270# ifdef VBOX_WITH_RESOURCE_USAGE_API
3271 PerformanceCollector *aCollector = m->pParent->i_performanceCollector();
3272# endif
3273 for (itOld = m->llNetIfs.begin(); itOld != m->llNetIfs.end(); ++itOld)
3274 {
3275 bool fGone = true;
3276 Bstr nameOld;
3277 (*itOld)->COMGETTER(Name)(nameOld.asOutParam());
3278 for (itNew = listCopy.begin(); itNew != listCopy.end(); ++itNew)
3279 {
3280 Bstr nameNew;
3281 (*itNew)->COMGETTER(Name)(nameNew.asOutParam());
3282 if (nameNew == nameOld)
3283 {
3284 fGone = false;
3285 (*itNew)->uninit();
3286 listCopy.erase(itNew);
3287 break;
3288 }
3289 }
3290 if (fGone)
3291 {
3292# ifdef VBOX_WITH_RESOURCE_USAGE_API
3293 (*itOld)->i_unregisterMetrics(aCollector, this);
3294 (*itOld)->uninit();
3295# endif
3296 }
3297 }
3298 /*
3299 * Need to set the references to VirtualBox object in all interface objects
3300 * (see @bugref{6439}).
3301 */
3302 for (itNew = list.begin(); itNew != list.end(); ++itNew)
3303 (*itNew)->i_setVirtualBox(m->pParent);
3304 /* At this point listCopy will contain newly discovered interfaces only. */
3305 for (itNew = listCopy.begin(); itNew != listCopy.end(); ++itNew)
3306 {
3307 HostNetworkInterfaceType_T t;
3308 HRESULT hrc = (*itNew)->COMGETTER(InterfaceType)(&t);
3309 if (FAILED(hrc))
3310 {
3311 Bstr n;
3312 (*itNew)->COMGETTER(Name)(n.asOutParam());
3313 LogRel(("Host::updateNetIfList: failed to get interface type for %ls\n", n.raw()));
3314 }
3315 else if (t == HostNetworkInterfaceType_Bridged)
3316 {
3317# ifdef VBOX_WITH_RESOURCE_USAGE_API
3318 (*itNew)->i_registerMetrics(aCollector, this);
3319# endif
3320 }
3321 }
3322 m->llNetIfs = list;
3323 return S_OK;
3324#else
3325 return E_NOTIMPL;
3326#endif
3327}
3328
3329#ifdef VBOX_WITH_RESOURCE_USAGE_API
3330
3331void Host::i_registerDiskMetrics(PerformanceCollector *aCollector)
3332{
3333 pm::CollectorHAL *hal = aCollector->getHAL();
3334 /* Create sub metrics */
3335 Utf8StrFmt fsNameBase("FS/{%s}/Usage", "/");
3336 //Utf8StrFmt fsNameBase("Filesystem/[root]/Usage");
3337 pm::SubMetric *fsRootUsageTotal = new pm::SubMetric(fsNameBase + "/Total",
3338 "Root file system size.");
3339 pm::SubMetric *fsRootUsageUsed = new pm::SubMetric(fsNameBase + "/Used",
3340 "Root file system space currently occupied.");
3341 pm::SubMetric *fsRootUsageFree = new pm::SubMetric(fsNameBase + "/Free",
3342 "Root file system space currently empty.");
3343
3344 pm::BaseMetric *fsRootUsage = new pm::HostFilesystemUsage(hal, this,
3345 fsNameBase, "/",
3346 fsRootUsageTotal,
3347 fsRootUsageUsed,
3348 fsRootUsageFree);
3349 aCollector->registerBaseMetric(fsRootUsage);
3350
3351 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageTotal, 0));
3352 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageTotal,
3353 new pm::AggregateAvg()));
3354 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageTotal,
3355 new pm::AggregateMin()));
3356 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageTotal,
3357 new pm::AggregateMax()));
3358
3359 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageUsed, 0));
3360 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageUsed,
3361 new pm::AggregateAvg()));
3362 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageUsed,
3363 new pm::AggregateMin()));
3364 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageUsed,
3365 new pm::AggregateMax()));
3366
3367 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageFree, 0));
3368 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageFree,
3369 new pm::AggregateAvg()));
3370 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageFree,
3371 new pm::AggregateMin()));
3372 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageFree,
3373 new pm::AggregateMax()));
3374
3375 /* For now we are concerned with the root file system only. */
3376 pm::DiskList disksUsage, disksLoad;
3377 int rc = hal->getDiskListByFs("/", disksUsage, disksLoad);
3378 if (RT_FAILURE(rc))
3379 return;
3380 pm::DiskList::iterator it;
3381 for (it = disksLoad.begin(); it != disksLoad.end(); ++it)
3382 {
3383 Utf8StrFmt strName("Disk/%s", it->c_str());
3384 pm::SubMetric *fsLoadUtil = new pm::SubMetric(strName + "/Load/Util",
3385 "Percentage of time disk was busy serving I/O requests.");
3386 pm::BaseMetric *fsLoad = new pm::HostDiskLoadRaw(hal, this, strName + "/Load",
3387 *it, fsLoadUtil);
3388 aCollector->registerBaseMetric(fsLoad);
3389
3390 aCollector->registerMetric(new pm::Metric(fsLoad, fsLoadUtil, 0));
3391 aCollector->registerMetric(new pm::Metric(fsLoad, fsLoadUtil,
3392 new pm::AggregateAvg()));
3393 aCollector->registerMetric(new pm::Metric(fsLoad, fsLoadUtil,
3394 new pm::AggregateMin()));
3395 aCollector->registerMetric(new pm::Metric(fsLoad, fsLoadUtil,
3396 new pm::AggregateMax()));
3397 }
3398 for (it = disksUsage.begin(); it != disksUsage.end(); ++it)
3399 {
3400 Utf8StrFmt strName("Disk/%s", it->c_str());
3401 pm::SubMetric *fsUsageTotal = new pm::SubMetric(strName + "/Usage/Total",
3402 "Disk size.");
3403 pm::BaseMetric *fsUsage = new pm::HostDiskUsage(hal, this, strName + "/Usage",
3404 *it, fsUsageTotal);
3405 aCollector->registerBaseMetric(fsUsage);
3406
3407 aCollector->registerMetric(new pm::Metric(fsUsage, fsUsageTotal, 0));
3408 aCollector->registerMetric(new pm::Metric(fsUsage, fsUsageTotal,
3409 new pm::AggregateAvg()));
3410 aCollector->registerMetric(new pm::Metric(fsUsage, fsUsageTotal,
3411 new pm::AggregateMin()));
3412 aCollector->registerMetric(new pm::Metric(fsUsage, fsUsageTotal,
3413 new pm::AggregateMax()));
3414 }
3415}
3416
3417void Host::i_registerMetrics(PerformanceCollector *aCollector)
3418{
3419 pm::CollectorHAL *hal = aCollector->getHAL();
3420 /* Create sub metrics */
3421 pm::SubMetric *cpuLoadUser = new pm::SubMetric("CPU/Load/User",
3422 "Percentage of processor time spent in user mode.");
3423 pm::SubMetric *cpuLoadKernel = new pm::SubMetric("CPU/Load/Kernel",
3424 "Percentage of processor time spent in kernel mode.");
3425 pm::SubMetric *cpuLoadIdle = new pm::SubMetric("CPU/Load/Idle",
3426 "Percentage of processor time spent idling.");
3427 pm::SubMetric *cpuMhzSM = new pm::SubMetric("CPU/MHz",
3428 "Average of current frequency of all processors.");
3429 pm::SubMetric *ramUsageTotal = new pm::SubMetric("RAM/Usage/Total",
3430 "Total physical memory installed.");
3431 pm::SubMetric *ramUsageUsed = new pm::SubMetric("RAM/Usage/Used",
3432 "Physical memory currently occupied.");
3433 pm::SubMetric *ramUsageFree = new pm::SubMetric("RAM/Usage/Free",
3434 "Physical memory currently available to applications.");
3435 pm::SubMetric *ramVMMUsed = new pm::SubMetric("RAM/VMM/Used",
3436 "Total physical memory used by the hypervisor.");
3437 pm::SubMetric *ramVMMFree = new pm::SubMetric("RAM/VMM/Free",
3438 "Total physical memory free inside the hypervisor.");
3439 pm::SubMetric *ramVMMBallooned = new pm::SubMetric("RAM/VMM/Ballooned",
3440 "Total physical memory ballooned by the hypervisor.");
3441 pm::SubMetric *ramVMMShared = new pm::SubMetric("RAM/VMM/Shared",
3442 "Total physical memory shared between VMs.");
3443
3444
3445 /* Create and register base metrics */
3446 pm::BaseMetric *cpuLoad = new pm::HostCpuLoadRaw(hal, this, cpuLoadUser, cpuLoadKernel,
3447 cpuLoadIdle);
3448 aCollector->registerBaseMetric(cpuLoad);
3449 pm::BaseMetric *cpuMhz = new pm::HostCpuMhz(hal, this, cpuMhzSM);
3450 aCollector->registerBaseMetric(cpuMhz);
3451 pm::BaseMetric *ramUsage = new pm::HostRamUsage(hal, this,
3452 ramUsageTotal,
3453 ramUsageUsed,
3454 ramUsageFree);
3455 aCollector->registerBaseMetric(ramUsage);
3456 pm::BaseMetric *ramVmm = new pm::HostRamVmm(aCollector->getGuestManager(), this,
3457 ramVMMUsed,
3458 ramVMMFree,
3459 ramVMMBallooned,
3460 ramVMMShared);
3461 aCollector->registerBaseMetric(ramVmm);
3462
3463 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser, 0));
3464 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
3465 new pm::AggregateAvg()));
3466 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
3467 new pm::AggregateMin()));
3468 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
3469 new pm::AggregateMax()));
3470
3471 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel, 0));
3472 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
3473 new pm::AggregateAvg()));
3474 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
3475 new pm::AggregateMin()));
3476 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
3477 new pm::AggregateMax()));
3478
3479 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle, 0));
3480 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
3481 new pm::AggregateAvg()));
3482 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
3483 new pm::AggregateMin()));
3484 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
3485 new pm::AggregateMax()));
3486
3487 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM, 0));
3488 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
3489 new pm::AggregateAvg()));
3490 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
3491 new pm::AggregateMin()));
3492 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
3493 new pm::AggregateMax()));
3494
3495 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal, 0));
3496 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
3497 new pm::AggregateAvg()));
3498 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
3499 new pm::AggregateMin()));
3500 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
3501 new pm::AggregateMax()));
3502
3503 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed, 0));
3504 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
3505 new pm::AggregateAvg()));
3506 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
3507 new pm::AggregateMin()));
3508 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
3509 new pm::AggregateMax()));
3510
3511 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree, 0));
3512 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
3513 new pm::AggregateAvg()));
3514 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
3515 new pm::AggregateMin()));
3516 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
3517 new pm::AggregateMax()));
3518
3519 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed, 0));
3520 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
3521 new pm::AggregateAvg()));
3522 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
3523 new pm::AggregateMin()));
3524 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
3525 new pm::AggregateMax()));
3526
3527 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree, 0));
3528 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
3529 new pm::AggregateAvg()));
3530 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
3531 new pm::AggregateMin()));
3532 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
3533 new pm::AggregateMax()));
3534
3535 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned, 0));
3536 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
3537 new pm::AggregateAvg()));
3538 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
3539 new pm::AggregateMin()));
3540 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
3541 new pm::AggregateMax()));
3542
3543 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared, 0));
3544 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
3545 new pm::AggregateAvg()));
3546 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
3547 new pm::AggregateMin()));
3548 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
3549 new pm::AggregateMax()));
3550 i_registerDiskMetrics(aCollector);
3551}
3552
3553void Host::i_unregisterMetrics(PerformanceCollector *aCollector)
3554{
3555 aCollector->unregisterMetricsFor(this);
3556 aCollector->unregisterBaseMetricsFor(this);
3557}
3558
3559#endif /* VBOX_WITH_RESOURCE_USAGE_API */
3560
3561
3562/* static */
3563void Host::i_generateMACAddress(Utf8Str &mac)
3564{
3565 /*
3566 * Our strategy is as follows: the first three bytes are our fixed
3567 * vendor ID (080027). The remaining 3 bytes will be taken from the
3568 * start of a GUID. This is a fairly safe algorithm.
3569 */
3570 Guid guid;
3571 guid.create();
3572 mac = Utf8StrFmt("080027%02X%02X%02X",
3573 guid.raw()->au8[0], guid.raw()->au8[1], guid.raw()->au8[2]);
3574}
3575
3576/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette