VirtualBox

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

Last change on this file since 55270 was 55251, checked in by vboxsync, 10 years ago

Main/Host: reduce the amount of unnecessary locking greatly

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

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