VirtualBox

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

Last change on this file since 76410 was 75919, checked in by vboxsync, 6 years ago

Main/Host: add new feature check for nested virtualization

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

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