VirtualBox

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

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

Main/USBProxyBackendUsbIp: Don't prevent VBoxSVC from starting when the server is not reachable, just try to reconnect every 3 seconds. Smaller other fixes for stale USB device lists when the server is not reachable and a fix for saving the same USB source multiple times

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

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