VirtualBox

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

Last change on this file since 46364 was 46340, checked in by vboxsync, 12 years ago

Host::init: Set HwVirt and NP to false when SUPR3QueryVTCaps fails.

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

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