VirtualBox

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

Last change on this file since 74897 was 72394, checked in by vboxsync, 7 years ago

HostDnsService: move monitor creation to proxy init.

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