VirtualBox

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

Last change on this file since 65810 was 65120, checked in by vboxsync, 8 years ago

Main: doxygen fixes

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