VirtualBox

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

Last change on this file since 46465 was 46434, checked in by vboxsync, 12 years ago

Main/Host: Put off calling VBoxOglIs3DAccelerationSupported till the information is actually requied. Saves spawning an extra child process every time Host() is instantiated.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 112.3 KB
Line 
1/* $Id: HostImpl.cpp 46434 2013-06-07 11:29:31Z 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? Tristate, -1 meaning not probed. */
213 int 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#ifdef VBOX_WITH_CROGL
382 /* Test for 3D hardware acceleration support later when (if ever) need. */
383 m->f3DAccelerationSupported = -1;
384#else
385 m->f3DAccelerationSupported = false;
386#endif
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 HRESULT hrc = autoCaller.rc();
1148 if (SUCCEEDED(hrc))
1149 {
1150 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1151 if (m->f3DAccelerationSupported != -1)
1152 *aSupported = m->f3DAccelerationSupported;
1153 else
1154 {
1155 alock.release();
1156#ifdef VBOX_WITH_CROGL
1157 bool fSupported = VBoxOglIs3DAccelerationSupported();
1158#else
1159 bool fSupported = false; /* shoudn't get here, but just in case. */
1160#endif
1161 AutoWriteLock alock2(this COMMA_LOCKVAL_SRC_POS);
1162 m->f3DAccelerationSupported = fSupported;
1163 alock2.release();
1164
1165 *aSupported = fSupported;
1166 }
1167 }
1168
1169#ifdef DEBUG_misha
1170 AssertMsgFailed(("should not be here any more!\n"));
1171#endif
1172
1173 return hrc;
1174}
1175
1176STDMETHODIMP Host::CreateHostOnlyNetworkInterface(IHostNetworkInterface **aHostNetworkInterface,
1177 IProgress **aProgress)
1178{
1179 CheckComArgOutPointerValid(aHostNetworkInterface);
1180 CheckComArgOutPointerValid(aProgress);
1181
1182 AutoCaller autoCaller(this);
1183 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1184
1185#ifdef VBOX_WITH_HOSTNETIF_API
1186 /* No need to lock anything. If there ever will - watch out, the function
1187 * called below grabs the VirtualBox lock. */
1188
1189 int r = NetIfCreateHostOnlyNetworkInterface(m->pParent, aHostNetworkInterface, aProgress);
1190 if (RT_SUCCESS(r))
1191 {
1192 if (!*aHostNetworkInterface)
1193 return setError(E_FAIL,
1194 tr("Unable to create a host network interface"));
1195
1196#if !defined(RT_OS_WINDOWS)
1197 Bstr tmpAddr, tmpMask, tmpName;
1198 HRESULT hrc;
1199 hrc = (*aHostNetworkInterface)->COMGETTER(Name)(tmpName.asOutParam());
1200 ComAssertComRCRet(hrc, hrc);
1201 hrc = (*aHostNetworkInterface)->COMGETTER(IPAddress)(tmpAddr.asOutParam());
1202 ComAssertComRCRet(hrc, hrc);
1203 hrc = (*aHostNetworkInterface)->COMGETTER(NetworkMask)(tmpMask.asOutParam());
1204 ComAssertComRCRet(hrc, hrc);
1205 /*
1206 * We need to write the default IP address and mask to extra data now,
1207 * so the interface gets re-created after vboxnetadp.ko reload.
1208 * Note that we avoid calling EnableStaticIpConfig since it would
1209 * change the address on host's interface as well and we want to
1210 * postpone the change until VM actually starts.
1211 */
1212 hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPAddress",
1213 tmpName.raw()).raw(),
1214 tmpAddr.raw());
1215 ComAssertComRCRet(hrc, hrc);
1216
1217 hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPNetMask",
1218 tmpName.raw()).raw(),
1219 tmpMask.raw());
1220 ComAssertComRCRet(hrc, hrc);
1221#endif
1222 }
1223
1224 return S_OK;
1225#else
1226 return E_NOTIMPL;
1227#endif
1228}
1229
1230STDMETHODIMP Host::RemoveHostOnlyNetworkInterface(IN_BSTR aId,
1231 IProgress **aProgress)
1232{
1233 CheckComArgOutPointerValid(aProgress);
1234
1235 AutoCaller autoCaller(this);
1236 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1237
1238#ifdef VBOX_WITH_HOSTNETIF_API
1239 /* No need to lock anything, the code below does not touch the state
1240 * of the host object. If that ever changes then check for lock order
1241 * violations with the called functions. */
1242
1243 Bstr name;
1244 HRESULT rc;
1245
1246 /* first check whether an interface with the given name already exists */
1247 {
1248 ComPtr<IHostNetworkInterface> iface;
1249 if (FAILED(FindHostNetworkInterfaceById(aId,
1250 iface.asOutParam())))
1251 return setError(VBOX_E_OBJECT_NOT_FOUND,
1252 tr("Host network interface with UUID {%RTuuid} does not exist"),
1253 Guid (aId).raw());
1254 rc = iface->COMGETTER(Name)(name.asOutParam());
1255 ComAssertComRCRet(rc, rc);
1256 }
1257
1258 int r = NetIfRemoveHostOnlyNetworkInterface(m->pParent, Guid(aId).ref(), aProgress);
1259 if (RT_SUCCESS(r))
1260 {
1261 /* Drop configuration parameters for removed interface */
1262 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPAddress", name.raw()).raw(), NULL);
1263 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPNetMask", name.raw()).raw(), NULL);
1264 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPV6Address", name.raw()).raw(), NULL);
1265 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPV6NetMask", name.raw()).raw(), NULL);
1266
1267 return S_OK;
1268 }
1269
1270 return r == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
1271#else
1272 return E_NOTIMPL;
1273#endif
1274}
1275
1276STDMETHODIMP Host::CreateUSBDeviceFilter(IN_BSTR aName,
1277 IHostUSBDeviceFilter **aFilter)
1278{
1279#ifdef VBOX_WITH_USB
1280 CheckComArgStrNotEmptyOrNull(aName);
1281 CheckComArgOutPointerValid(aFilter);
1282
1283 AutoCaller autoCaller(this);
1284 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1285
1286 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1287
1288 ComObjPtr<HostUSBDeviceFilter> filter;
1289 filter.createObject();
1290 HRESULT rc = filter->init(this, aName);
1291 ComAssertComRCRet(rc, rc);
1292 rc = filter.queryInterfaceTo(aFilter);
1293 AssertComRCReturn(rc, rc);
1294 return S_OK;
1295#else
1296 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1297 * extended error info to indicate that USB is simply not available
1298 * (w/o treating it as a failure), for example, as in OSE. */
1299 NOREF(aName);
1300 NOREF(aFilter);
1301 ReturnComNotImplemented();
1302#endif
1303}
1304
1305STDMETHODIMP Host::InsertUSBDeviceFilter(ULONG aPosition,
1306 IHostUSBDeviceFilter *aFilter)
1307{
1308#ifdef VBOX_WITH_USB
1309 CheckComArgNotNull(aFilter);
1310
1311 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1312 AutoCaller autoCaller(this);
1313 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1314
1315 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1316
1317 clearError();
1318 MultiResult rc = checkUSBProxyService();
1319 if (FAILED(rc)) return rc;
1320
1321 ComObjPtr<HostUSBDeviceFilter> pFilter;
1322 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
1323 it != m->llChildren.end();
1324 ++it)
1325 {
1326 if (*it == aFilter)
1327 {
1328 pFilter = *it;
1329 break;
1330 }
1331 }
1332 if (pFilter.isNull())
1333 return setError(VBOX_E_INVALID_OBJECT_STATE,
1334 tr("The given USB device filter is not created within this VirtualBox instance"));
1335
1336 if (pFilter->mInList)
1337 return setError(E_INVALIDARG,
1338 tr("The given USB device filter is already in the list"));
1339
1340 /* iterate to the position... */
1341 USBDeviceFilterList::iterator itPos = m->llUSBDeviceFilters.begin();
1342 std::advance(itPos, aPosition);
1343 /* ...and insert */
1344 m->llUSBDeviceFilters.insert(itPos, pFilter);
1345 pFilter->mInList = true;
1346
1347 /* notify the proxy (only when the filter is active) */
1348 if ( m->pUSBProxyService->isActive()
1349 && pFilter->getData().mActive)
1350 {
1351 ComAssertRet(pFilter->getId() == NULL, E_FAIL);
1352 pFilter->getId() = m->pUSBProxyService->insertFilter(&pFilter->getData().mUSBFilter);
1353 }
1354
1355 // save the global settings; for that we should hold only the VirtualBox lock
1356 alock.release();
1357 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
1358 return rc = m->pParent->saveSettings();
1359#else
1360 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1361 * extended error info to indicate that USB is simply not available
1362 * (w/o treating it as a failure), for example, as in OSE. */
1363 NOREF(aPosition);
1364 NOREF(aFilter);
1365 ReturnComNotImplemented();
1366#endif
1367}
1368
1369STDMETHODIMP Host::RemoveUSBDeviceFilter(ULONG aPosition)
1370{
1371#ifdef VBOX_WITH_USB
1372
1373 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1374 AutoCaller autoCaller(this);
1375 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1376
1377 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1378
1379 clearError();
1380 MultiResult rc = checkUSBProxyService();
1381 if (FAILED(rc)) return rc;
1382
1383 if (!m->llUSBDeviceFilters.size())
1384 return setError(E_INVALIDARG,
1385 tr("The USB device filter list is empty"));
1386
1387 if (aPosition >= m->llUSBDeviceFilters.size())
1388 return setError(E_INVALIDARG,
1389 tr("Invalid position: %lu (must be in range [0, %lu])"),
1390 aPosition, m->llUSBDeviceFilters.size() - 1);
1391
1392 ComObjPtr<HostUSBDeviceFilter> filter;
1393 {
1394 /* iterate to the position... */
1395 USBDeviceFilterList::iterator it = m->llUSBDeviceFilters.begin();
1396 std::advance (it, aPosition);
1397 /* ...get an element from there... */
1398 filter = *it;
1399 /* ...and remove */
1400 filter->mInList = false;
1401 m->llUSBDeviceFilters.erase(it);
1402 }
1403
1404 /* notify the proxy (only when the filter is active) */
1405 if (m->pUSBProxyService->isActive() && filter->getData().mActive)
1406 {
1407 ComAssertRet(filter->getId() != NULL, E_FAIL);
1408 m->pUSBProxyService->removeFilter(filter->getId());
1409 filter->getId() = NULL;
1410 }
1411
1412 // save the global settings; for that we should hold only the VirtualBox lock
1413 alock.release();
1414 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
1415 return rc = m->pParent->saveSettings();
1416#else
1417 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1418 * extended error info to indicate that USB is simply not available
1419 * (w/o treating it as a failure), for example, as in OSE. */
1420 NOREF(aPosition);
1421 ReturnComNotImplemented();
1422#endif
1423}
1424
1425STDMETHODIMP Host::FindHostDVDDrive(IN_BSTR aName, IMedium **aDrive)
1426{
1427 CheckComArgStrNotEmptyOrNull(aName);
1428 CheckComArgOutPointerValid(aDrive);
1429
1430 ComObjPtr<Medium>medium;
1431 HRESULT rc = findHostDriveByNameOrId(DeviceType_DVD, Utf8Str(aName), medium);
1432 if (SUCCEEDED(rc))
1433 return medium.queryInterfaceTo(aDrive);
1434 else
1435 return setError(rc, Medium::tr("The host DVD drive named '%ls' could not be found"), aName);
1436}
1437
1438STDMETHODIMP Host::FindHostFloppyDrive(IN_BSTR aName, IMedium **aDrive)
1439{
1440 CheckComArgStrNotEmptyOrNull(aName);
1441 CheckComArgOutPointerValid(aDrive);
1442
1443 *aDrive = NULL;
1444
1445 ComObjPtr<Medium>medium;
1446 HRESULT rc = findHostDriveByNameOrId(DeviceType_Floppy, Utf8Str(aName), medium);
1447 if (SUCCEEDED(rc))
1448 return medium.queryInterfaceTo(aDrive);
1449 else
1450 return setError(rc, Medium::tr("The host floppy drive named '%ls' could not be found"), aName);
1451}
1452
1453STDMETHODIMP Host::FindHostNetworkInterfaceByName(IN_BSTR name, IHostNetworkInterface **networkInterface)
1454{
1455#ifndef VBOX_WITH_HOSTNETIF_API
1456 return E_NOTIMPL;
1457#else
1458 if (!name)
1459 return E_INVALIDARG;
1460 if (!networkInterface)
1461 return E_POINTER;
1462
1463 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1464
1465 *networkInterface = NULL;
1466 ComObjPtr<HostNetworkInterface> found;
1467 int rc = updateNetIfList();
1468 if (RT_FAILURE(rc))
1469 {
1470 Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
1471 return E_FAIL;
1472 }
1473 HostNetworkInterfaceList::iterator it;
1474 for (it = m->llNetIfs.begin(); it != m->llNetIfs.end(); ++it)
1475 {
1476 Bstr n;
1477 (*it)->COMGETTER(Name) (n.asOutParam());
1478 if (n == name)
1479 found = *it;
1480 }
1481
1482 if (!found)
1483 return setError(E_INVALIDARG,
1484 HostNetworkInterface::tr("The host network interface with the given name could not be found"));
1485
1486 return found.queryInterfaceTo(networkInterface);
1487#endif
1488}
1489
1490STDMETHODIMP Host::FindHostNetworkInterfaceById(IN_BSTR id, IHostNetworkInterface **networkInterface)
1491{
1492#ifndef VBOX_WITH_HOSTNETIF_API
1493 return E_NOTIMPL;
1494#else
1495 if (!Guid(id).isValid())
1496 return E_INVALIDARG;
1497 if (!networkInterface)
1498 return E_POINTER;
1499
1500 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1501
1502 *networkInterface = NULL;
1503 ComObjPtr<HostNetworkInterface> found;
1504 int rc = updateNetIfList();
1505 if (RT_FAILURE(rc))
1506 {
1507 Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
1508 return E_FAIL;
1509 }
1510 HostNetworkInterfaceList::iterator it;
1511 for (it = m->llNetIfs.begin(); it != m->llNetIfs.end(); ++it)
1512 {
1513 Bstr g;
1514 (*it)->COMGETTER(Id) (g.asOutParam());
1515 if (g == id)
1516 found = *it;
1517 }
1518
1519 if (!found)
1520 return setError(E_INVALIDARG,
1521 HostNetworkInterface::tr("The host network interface with the given GUID could not be found"));
1522
1523 return found.queryInterfaceTo(networkInterface);
1524#endif
1525}
1526
1527STDMETHODIMP Host::FindHostNetworkInterfacesOfType(HostNetworkInterfaceType_T type,
1528 ComSafeArrayOut(IHostNetworkInterface *, aNetworkInterfaces))
1529{
1530#ifdef VBOX_WITH_HOSTNETIF_API
1531 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1532
1533 int rc = updateNetIfList();
1534 if (RT_FAILURE(rc))
1535 return E_FAIL;
1536
1537 HostNetworkInterfaceList resultList;
1538
1539 HostNetworkInterfaceList::iterator it;
1540 for (it = m->llNetIfs.begin(); it != m->llNetIfs.end(); ++it)
1541 {
1542 HostNetworkInterfaceType_T t;
1543 HRESULT hr = (*it)->COMGETTER(InterfaceType)(&t);
1544 if (FAILED(hr))
1545 return hr;
1546
1547 if (t == type)
1548 resultList.push_back (*it);
1549 }
1550
1551 SafeIfaceArray<IHostNetworkInterface> filteredNetworkInterfaces (resultList);
1552 filteredNetworkInterfaces.detachTo(ComSafeArrayOutArg(aNetworkInterfaces));
1553
1554 return S_OK;
1555#else
1556 return E_NOTIMPL;
1557#endif
1558}
1559
1560STDMETHODIMP Host::FindUSBDeviceByAddress(IN_BSTR aAddress,
1561 IHostUSBDevice **aDevice)
1562{
1563#ifdef VBOX_WITH_USB
1564 CheckComArgStrNotEmptyOrNull(aAddress);
1565 CheckComArgOutPointerValid(aDevice);
1566
1567 *aDevice = NULL;
1568
1569 SafeIfaceArray<IHostUSBDevice> devsvec;
1570 HRESULT rc = COMGETTER(USBDevices) (ComSafeArrayAsOutParam(devsvec));
1571 if (FAILED(rc)) return rc;
1572
1573 for (size_t i = 0; i < devsvec.size(); ++i)
1574 {
1575 Bstr address;
1576 rc = devsvec[i]->COMGETTER(Address) (address.asOutParam());
1577 if (FAILED(rc)) return rc;
1578 if (address == aAddress)
1579 {
1580 return ComObjPtr<IHostUSBDevice> (devsvec[i]).queryInterfaceTo(aDevice);
1581 }
1582 }
1583
1584 return setErrorNoLog(VBOX_E_OBJECT_NOT_FOUND,
1585 tr("Could not find a USB device with address '%ls'"),
1586 aAddress);
1587
1588#else /* !VBOX_WITH_USB */
1589 NOREF(aAddress);
1590 NOREF(aDevice);
1591 return E_NOTIMPL;
1592#endif /* !VBOX_WITH_USB */
1593}
1594
1595STDMETHODIMP Host::FindUSBDeviceById(IN_BSTR aId,
1596 IHostUSBDevice **aDevice)
1597{
1598#ifdef VBOX_WITH_USB
1599 CheckComArgExpr(aId, Guid (aId).isValid());
1600 CheckComArgOutPointerValid(aDevice);
1601
1602 *aDevice = NULL;
1603
1604 SafeIfaceArray<IHostUSBDevice> devsvec;
1605 HRESULT rc = COMGETTER(USBDevices) (ComSafeArrayAsOutParam(devsvec));
1606 if (FAILED(rc)) return rc;
1607
1608 for (size_t i = 0; i < devsvec.size(); ++i)
1609 {
1610 Bstr id;
1611 rc = devsvec[i]->COMGETTER(Id) (id.asOutParam());
1612 if (FAILED(rc)) return rc;
1613 if (id == aId)
1614 {
1615 return ComObjPtr<IHostUSBDevice> (devsvec[i]).queryInterfaceTo(aDevice);
1616 }
1617 }
1618
1619 return setErrorNoLog (VBOX_E_OBJECT_NOT_FOUND, tr (
1620 "Could not find a USB device with uuid {%RTuuid}"),
1621 Guid (aId).raw());
1622
1623#else /* !VBOX_WITH_USB */
1624 NOREF(aId);
1625 NOREF(aDevice);
1626 return E_NOTIMPL;
1627#endif /* !VBOX_WITH_USB */
1628}
1629
1630STDMETHODIMP Host::GenerateMACAddress(BSTR *aAddress)
1631{
1632 CheckComArgOutPointerValid(aAddress);
1633 // no locking required
1634 Utf8Str mac;
1635 generateMACAddress(mac);
1636 Bstr(mac).cloneTo(aAddress);
1637 return S_OK;
1638}
1639
1640// public methods only for internal purposes
1641////////////////////////////////////////////////////////////////////////////////
1642
1643HRESULT Host::loadSettings(const settings::Host &data)
1644{
1645 HRESULT rc = S_OK;
1646#ifdef VBOX_WITH_USB
1647 AutoCaller autoCaller(this);
1648 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1649
1650 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1651
1652 for (settings::USBDeviceFiltersList::const_iterator it = data.llUSBDeviceFilters.begin();
1653 it != data.llUSBDeviceFilters.end();
1654 ++it)
1655 {
1656 const settings::USBDeviceFilter &f = *it;
1657 ComObjPtr<HostUSBDeviceFilter> pFilter;
1658 pFilter.createObject();
1659 rc = pFilter->init(this, f);
1660 if (FAILED(rc)) break;
1661
1662 m->llUSBDeviceFilters.push_back(pFilter);
1663 pFilter->mInList = true;
1664
1665 /* notify the proxy (only when the filter is active) */
1666 if (pFilter->getData().mActive)
1667 {
1668 HostUSBDeviceFilter *flt = pFilter; /* resolve ambiguity */
1669 flt->getId() = m->pUSBProxyService->insertFilter(&pFilter->getData().mUSBFilter);
1670 }
1671 }
1672#else
1673 NOREF(data);
1674#endif /* VBOX_WITH_USB */
1675 return rc;
1676}
1677
1678HRESULT Host::saveSettings(settings::Host &data)
1679{
1680#ifdef VBOX_WITH_USB
1681 AutoCaller autoCaller(this);
1682 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1683
1684 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1685
1686 data.llUSBDeviceFilters.clear();
1687
1688 for (USBDeviceFilterList::const_iterator it = m->llUSBDeviceFilters.begin();
1689 it != m->llUSBDeviceFilters.end();
1690 ++it)
1691 {
1692 ComObjPtr<HostUSBDeviceFilter> pFilter = *it;
1693 settings::USBDeviceFilter f;
1694 pFilter->saveSettings(f);
1695 data.llUSBDeviceFilters.push_back(f);
1696 }
1697#else
1698 NOREF(data);
1699#endif /* VBOX_WITH_USB */
1700
1701 return S_OK;
1702}
1703
1704/**
1705 * Sets the given pointer to point to the static list of DVD or floppy
1706 * drives in the Host instance data, depending on the @a mediumType
1707 * parameter.
1708 *
1709 * This builds the list on the first call; it adds or removes host drives
1710 * that may have changed if fRefresh == true.
1711 *
1712 * The caller must hold the medium tree write lock before calling this.
1713 * To protect the list to which the caller's pointer points, the caller
1714 * must also hold that lock.
1715 *
1716 * @param mediumType Must be DeviceType_Floppy or DeviceType_DVD.
1717 * @param fRefresh Whether to refresh the host drives list even if this is not the first call.
1718 * @param pll Caller's pointer which gets set to the static list of host drives.
1719 * @return
1720 */
1721HRESULT Host::getDrives(DeviceType_T mediumType,
1722 bool fRefresh,
1723 MediaList *&pll)
1724{
1725 HRESULT rc = S_OK;
1726 Assert(m->pParent->getMediaTreeLockHandle().isWriteLockOnCurrentThread());
1727
1728 MediaList llNew;
1729 MediaList *pllCached;
1730 bool *pfListBuilt = NULL;
1731
1732 switch (mediumType)
1733 {
1734 case DeviceType_DVD:
1735 if (!m->fDVDDrivesListBuilt || fRefresh)
1736 {
1737 rc = buildDVDDrivesList(llNew);
1738 if (FAILED(rc))
1739 return rc;
1740 pfListBuilt = &m->fDVDDrivesListBuilt;
1741 }
1742 pllCached = &m->llDVDDrives;
1743 break;
1744
1745 case DeviceType_Floppy:
1746 if (!m->fFloppyDrivesListBuilt || fRefresh)
1747 {
1748 rc = buildFloppyDrivesList(llNew);
1749 if (FAILED(rc))
1750 return rc;
1751 pfListBuilt = &m->fFloppyDrivesListBuilt;
1752 }
1753 pllCached = &m->llFloppyDrives;
1754 break;
1755
1756 default:
1757 return E_INVALIDARG;
1758 }
1759
1760 if (pfListBuilt)
1761 {
1762 // a list was built in llNew above:
1763 if (!*pfListBuilt)
1764 {
1765 // this was the first call (instance bool is still false): then just copy the whole list and return
1766 *pllCached = llNew;
1767 // and mark the instance data as "built"
1768 *pfListBuilt = true;
1769 }
1770 else
1771 {
1772 // list was built, and this was a subsequent call: then compare the old and the new lists
1773
1774 // remove drives from the cached list which are no longer present
1775 for (MediaList::iterator itCached = pllCached->begin();
1776 itCached != pllCached->end();
1777 /*nothing */)
1778 {
1779 Medium *pCached = *itCached;
1780 const Utf8Str strLocationCached = pCached->getLocationFull();
1781 bool fFound = false;
1782 for (MediaList::iterator itNew = llNew.begin();
1783 itNew != llNew.end();
1784 ++itNew)
1785 {
1786 Medium *pNew = *itNew;
1787 const Utf8Str strLocationNew = pNew->getLocationFull();
1788 if (strLocationNew == strLocationCached)
1789 {
1790 fFound = true;
1791 break;
1792 }
1793 }
1794 if (!fFound)
1795 itCached = pllCached->erase(itCached);
1796 else
1797 ++itCached;
1798 }
1799
1800 // add drives to the cached list that are not on there yet
1801 for (MediaList::iterator itNew = llNew.begin();
1802 itNew != llNew.end();
1803 ++itNew)
1804 {
1805 Medium *pNew = *itNew;
1806 const Utf8Str strLocationNew = pNew->getLocationFull();
1807 bool fFound = false;
1808 for (MediaList::iterator itCached = pllCached->begin();
1809 itCached != pllCached->end();
1810 ++itCached)
1811 {
1812 Medium *pCached = *itCached;
1813 const Utf8Str strLocationCached = pCached->getLocationFull();
1814 if (strLocationNew == strLocationCached)
1815 {
1816 fFound = true;
1817 break;
1818 }
1819 }
1820
1821 if (!fFound)
1822 pllCached->push_back(pNew);
1823 }
1824 }
1825 }
1826
1827 // return cached list to caller
1828 pll = pllCached;
1829
1830 return rc;
1831}
1832
1833/**
1834 * Goes through the list of host drives that would be returned by getDrives()
1835 * and looks for a host drive with the given UUID. If found, it sets pMedium
1836 * to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
1837 *
1838 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
1839 * @param uuid Medium UUID of host drive to look for.
1840 * @param fRefresh Whether to refresh the host drives list (see getDrives())
1841 * @param pMedium Medium object, if found…
1842 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
1843 */
1844HRESULT Host::findHostDriveById(DeviceType_T mediumType,
1845 const Guid &uuid,
1846 bool fRefresh,
1847 ComObjPtr<Medium> &pMedium)
1848{
1849 MediaList *pllMedia;
1850
1851 AutoWriteLock wlock(m->pParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
1852 HRESULT rc = getDrives(mediumType, fRefresh, pllMedia);
1853 if (SUCCEEDED(rc))
1854 {
1855 for (MediaList::iterator it = pllMedia->begin();
1856 it != pllMedia->end();
1857 ++it)
1858 {
1859 Medium *pThis = *it;
1860 AutoCaller mediumCaller(pThis);
1861 AutoReadLock mediumLock(pThis COMMA_LOCKVAL_SRC_POS);
1862 if (pThis->getId() == uuid)
1863 {
1864 pMedium = pThis;
1865 return S_OK;
1866 }
1867 }
1868 }
1869
1870 return VBOX_E_OBJECT_NOT_FOUND;
1871}
1872
1873/**
1874 * Goes through the list of host drives that would be returned by getDrives()
1875 * and looks for a host drive with the given name. If found, it sets pMedium
1876 * to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
1877 *
1878 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
1879 * @param strLocationFull Name (path) of host drive to look for.
1880 * @param fRefresh Whether to refresh the host drives list (see getDrives())
1881 * @param pMedium Medium object, if found…
1882 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
1883 */
1884HRESULT Host::findHostDriveByName(DeviceType_T mediumType,
1885 const Utf8Str &strLocationFull,
1886 bool fRefresh,
1887 ComObjPtr<Medium> &pMedium)
1888{
1889 MediaList *pllMedia;
1890
1891 AutoWriteLock wlock(m->pParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
1892 HRESULT rc = getDrives(mediumType, fRefresh, pllMedia);
1893 if (SUCCEEDED(rc))
1894 {
1895 for (MediaList::iterator it = pllMedia->begin();
1896 it != pllMedia->end();
1897 ++it)
1898 {
1899 Medium *pThis = *it;
1900 AutoCaller mediumCaller(pThis);
1901 AutoReadLock mediumLock(pThis COMMA_LOCKVAL_SRC_POS);
1902 if (pThis->getLocationFull() == strLocationFull)
1903 {
1904 pMedium = pThis;
1905 return S_OK;
1906 }
1907 }
1908 }
1909
1910 return VBOX_E_OBJECT_NOT_FOUND;
1911}
1912
1913/**
1914 * Goes through the list of host drives that would be returned by getDrives()
1915 * and looks for a host drive with the given name, location or ID. If found,
1916 * it sets pMedium to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
1917 *
1918 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
1919 * @param strNameOrId Name or full location or UUID of host drive to look for.
1920 * @param pMedium Medium object, if found…
1921 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
1922 */
1923HRESULT Host::findHostDriveByNameOrId(DeviceType_T mediumType,
1924 const Utf8Str &strNameOrId,
1925 ComObjPtr<Medium> &pMedium)
1926{
1927 AutoWriteLock wlock(m->pParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
1928
1929 Guid uuid(strNameOrId);
1930 if (uuid.isValid() && !uuid.isZero())
1931 return findHostDriveById(mediumType, uuid, true /* fRefresh */, pMedium);
1932
1933 // string is not a syntactically valid UUID: try a name then
1934 return findHostDriveByName(mediumType, strNameOrId, true /* fRefresh */, pMedium);
1935}
1936
1937/**
1938 * Called from getDrives() to build the DVD drives list.
1939 * @param pll
1940 * @return
1941 */
1942HRESULT Host::buildDVDDrivesList(MediaList &list)
1943{
1944 HRESULT rc = S_OK;
1945
1946 Assert(m->pParent->getMediaTreeLockHandle().isWriteLockOnCurrentThread());
1947
1948 try
1949 {
1950#if defined(RT_OS_WINDOWS)
1951 int sz = GetLogicalDriveStrings(0, NULL);
1952 TCHAR *hostDrives = new TCHAR[sz+1];
1953 GetLogicalDriveStrings(sz, hostDrives);
1954 wchar_t driveName[3] = { '?', ':', '\0' };
1955 TCHAR *p = hostDrives;
1956 do
1957 {
1958 if (GetDriveType(p) == DRIVE_CDROM)
1959 {
1960 driveName[0] = *p;
1961 ComObjPtr<Medium> hostDVDDriveObj;
1962 hostDVDDriveObj.createObject();
1963 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(driveName));
1964 list.push_back(hostDVDDriveObj);
1965 }
1966 p += _tcslen(p) + 1;
1967 }
1968 while (*p);
1969 delete[] hostDrives;
1970
1971#elif defined(RT_OS_SOLARIS)
1972# ifdef VBOX_USE_LIBHAL
1973 if (!getDVDInfoFromHal(list))
1974# endif
1975 {
1976 getDVDInfoFromDevTree(list);
1977 }
1978
1979#elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
1980 if (RT_SUCCESS(m->hostDrives.updateDVDs()))
1981 for (DriveInfoList::const_iterator it = m->hostDrives.DVDBegin();
1982 SUCCEEDED(rc) && it != m->hostDrives.DVDEnd(); ++it)
1983 {
1984 ComObjPtr<Medium> hostDVDDriveObj;
1985 Utf8Str location(it->mDevice);
1986 Utf8Str description(it->mDescription);
1987 if (SUCCEEDED(rc))
1988 rc = hostDVDDriveObj.createObject();
1989 if (SUCCEEDED(rc))
1990 rc = hostDVDDriveObj->init(m->pParent, DeviceType_DVD, location, description);
1991 if (SUCCEEDED(rc))
1992 list.push_back(hostDVDDriveObj);
1993 }
1994#elif defined(RT_OS_DARWIN)
1995 PDARWINDVD cur = DarwinGetDVDDrives();
1996 while (cur)
1997 {
1998 ComObjPtr<Medium> hostDVDDriveObj;
1999 hostDVDDriveObj.createObject();
2000 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(cur->szName));
2001 list.push_back(hostDVDDriveObj);
2002
2003 /* next */
2004 void *freeMe = cur;
2005 cur = cur->pNext;
2006 RTMemFree(freeMe);
2007 }
2008#else
2009 /* PORTME */
2010#endif
2011 }
2012 catch(std::bad_alloc &)
2013 {
2014 rc = E_OUTOFMEMORY;
2015 }
2016 return rc;
2017}
2018
2019/**
2020 * Called from getDrives() to build the floppy drives list.
2021 * @param list
2022 * @return
2023 */
2024HRESULT Host::buildFloppyDrivesList(MediaList &list)
2025{
2026 HRESULT rc = S_OK;
2027
2028 Assert(m->pParent->getMediaTreeLockHandle().isWriteLockOnCurrentThread());
2029
2030 try
2031 {
2032#ifdef RT_OS_WINDOWS
2033 int sz = GetLogicalDriveStrings(0, NULL);
2034 TCHAR *hostDrives = new TCHAR[sz+1];
2035 GetLogicalDriveStrings(sz, hostDrives);
2036 wchar_t driveName[3] = { '?', ':', '\0' };
2037 TCHAR *p = hostDrives;
2038 do
2039 {
2040 if (GetDriveType(p) == DRIVE_REMOVABLE)
2041 {
2042 driveName[0] = *p;
2043 ComObjPtr<Medium> hostFloppyDriveObj;
2044 hostFloppyDriveObj.createObject();
2045 hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, Bstr(driveName));
2046 list.push_back(hostFloppyDriveObj);
2047 }
2048 p += _tcslen(p) + 1;
2049 }
2050 while (*p);
2051 delete[] hostDrives;
2052#elif defined(RT_OS_LINUX)
2053 if (RT_SUCCESS(m->hostDrives.updateFloppies()))
2054 for (DriveInfoList::const_iterator it = m->hostDrives.FloppyBegin();
2055 SUCCEEDED(rc) && it != m->hostDrives.FloppyEnd(); ++it)
2056 {
2057 ComObjPtr<Medium> hostFloppyDriveObj;
2058 Utf8Str location(it->mDevice);
2059 Utf8Str description(it->mDescription);
2060 if (SUCCEEDED(rc))
2061 rc = hostFloppyDriveObj.createObject();
2062 if (SUCCEEDED(rc))
2063 rc = hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, location, description);
2064 if (SUCCEEDED(rc))
2065 list.push_back(hostFloppyDriveObj);
2066 }
2067#else
2068 NOREF(list);
2069 /* PORTME */
2070#endif
2071 }
2072 catch(std::bad_alloc &)
2073 {
2074 rc = E_OUTOFMEMORY;
2075 }
2076
2077 return rc;
2078}
2079
2080#ifdef VBOX_WITH_USB
2081USBProxyService* Host::usbProxyService()
2082{
2083 return m->pUSBProxyService;
2084}
2085
2086HRESULT Host::addChild(HostUSBDeviceFilter *pChild)
2087{
2088 AutoCaller autoCaller(this);
2089 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2090
2091 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2092
2093 m->llChildren.push_back(pChild);
2094
2095 return S_OK;
2096}
2097
2098HRESULT Host::removeChild(HostUSBDeviceFilter *pChild)
2099{
2100 AutoCaller autoCaller(this);
2101 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2102
2103 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2104
2105 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
2106 it != m->llChildren.end();
2107 ++it)
2108 {
2109 if (*it == pChild)
2110 {
2111 m->llChildren.erase(it);
2112 break;
2113 }
2114 }
2115
2116 return S_OK;
2117}
2118
2119VirtualBox* Host::parent()
2120{
2121 return m->pParent;
2122}
2123
2124/**
2125 * Called by setter methods of all USB device filters.
2126 */
2127HRESULT Host::onUSBDeviceFilterChange(HostUSBDeviceFilter *aFilter,
2128 BOOL aActiveChanged /* = FALSE */)
2129{
2130 AutoCaller autoCaller(this);
2131 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2132
2133 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2134
2135 if (aFilter->mInList)
2136 {
2137 if (aActiveChanged)
2138 {
2139 // insert/remove the filter from the proxy
2140 if (aFilter->getData().mActive)
2141 {
2142 ComAssertRet(aFilter->getId() == NULL, E_FAIL);
2143 aFilter->getId() = m->pUSBProxyService->insertFilter(&aFilter->getData().mUSBFilter);
2144 }
2145 else
2146 {
2147 ComAssertRet(aFilter->getId() != NULL, E_FAIL);
2148 m->pUSBProxyService->removeFilter(aFilter->getId());
2149 aFilter->getId() = NULL;
2150 }
2151 }
2152 else
2153 {
2154 if (aFilter->getData().mActive)
2155 {
2156 // update the filter in the proxy
2157 ComAssertRet(aFilter->getId() != NULL, E_FAIL);
2158 m->pUSBProxyService->removeFilter(aFilter->getId());
2159 aFilter->getId() = m->pUSBProxyService->insertFilter(&aFilter->getData().mUSBFilter);
2160 }
2161 }
2162
2163 // save the global settings... yeah, on every single filter property change
2164 // for that we should hold only the VirtualBox lock
2165 alock.release();
2166 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
2167 return m->pParent->saveSettings();
2168 }
2169
2170 return S_OK;
2171}
2172
2173
2174/**
2175 * Interface for obtaining a copy of the USBDeviceFilterList,
2176 * used by the USBProxyService.
2177 *
2178 * @param aGlobalFilters Where to put the global filter list copy.
2179 * @param aMachines Where to put the machine vector.
2180 */
2181void Host::getUSBFilters(Host::USBDeviceFilterList *aGlobalFilters)
2182{
2183 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2184
2185 *aGlobalFilters = m->llUSBDeviceFilters;
2186}
2187
2188#endif /* VBOX_WITH_USB */
2189
2190// private methods
2191////////////////////////////////////////////////////////////////////////////////
2192
2193#if defined(RT_OS_SOLARIS) && defined(VBOX_USE_LIBHAL)
2194
2195/**
2196 * Helper function to get the slice number from a device path
2197 *
2198 * @param pszDevLinkPath Pointer to a device path (/dev/(r)dsk/c7d1t0d0s3 etc.)
2199 * @returns Pointer to the slice portion of the given path.
2200 */
2201static char *solarisGetSliceFromPath(const char *pszDevLinkPath)
2202{
2203 char *pszFound = NULL;
2204 char *pszSlice = strrchr(pszDevLinkPath, 's');
2205 char *pszDisk = strrchr(pszDevLinkPath, 'd');
2206 if (pszSlice && pszSlice > pszDisk)
2207 pszFound = pszSlice;
2208 else
2209 pszFound = pszDisk;
2210
2211 if (pszFound && RT_C_IS_DIGIT(pszFound[1]))
2212 return pszFound;
2213
2214 return NULL;
2215}
2216
2217/**
2218 * Walk device links and returns an allocated path for the first one in the snapshot.
2219 *
2220 * @param DevLink Handle to the device link being walked.
2221 * @param pvArg Opaque data containing the pointer to the path.
2222 * @returns Pointer to an allocated device path string.
2223 */
2224static int solarisWalkDevLink(di_devlink_t DevLink, void *pvArg)
2225{
2226 char **ppszPath = (char **)pvArg;
2227 *ppszPath = strdup(di_devlink_path(DevLink));
2228 return DI_WALK_TERMINATE;
2229}
2230
2231/**
2232 * Walk all devices in the system and enumerate CD/DVD drives.
2233 * @param Node Handle to the current node.
2234 * @param pvArg Opaque data (holds list pointer).
2235 * @returns Solaris specific code whether to continue walking or not.
2236 */
2237static int solarisWalkDeviceNodeForDVD(di_node_t Node, void *pvArg)
2238{
2239 PSOLARISDVD *ppDrives = (PSOLARISDVD *)pvArg;
2240
2241 /*
2242 * Check for "removable-media" or "hotpluggable" instead of "SCSI" so that we also include USB CD-ROMs.
2243 * As unfortunately the Solaris drivers only export these common properties.
2244 */
2245 int *pInt = NULL;
2246 if ( di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "removable-media", &pInt) >= 0
2247 || di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "hotpluggable", &pInt) >= 0)
2248 {
2249 if (di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "inquiry-device-type", &pInt) > 0
2250 && ( *pInt == DTYPE_RODIRECT /* CDROM */
2251 || *pInt == DTYPE_OPTICAL)) /* Optical Drive */
2252 {
2253 char *pszProduct = NULL;
2254 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-product-id", &pszProduct) > 0)
2255 {
2256 char *pszVendor = NULL;
2257 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-vendor-id", &pszVendor) > 0)
2258 {
2259 /*
2260 * Found a DVD drive, we need to scan the minor nodes to find the correct
2261 * slice that represents the whole drive. "s2" is always the whole drive for CD/DVDs.
2262 */
2263 int Major = di_driver_major(Node);
2264 di_minor_t Minor = DI_MINOR_NIL;
2265 di_devlink_handle_t DevLink = di_devlink_init(NULL /* name */, 0 /* flags */);
2266 if (DevLink)
2267 {
2268 while ((Minor = di_minor_next(Node, Minor)) != DI_MINOR_NIL)
2269 {
2270 dev_t Dev = di_minor_devt(Minor);
2271 if ( Major != (int)major(Dev)
2272 || di_minor_spectype(Minor) == S_IFBLK
2273 || di_minor_type(Minor) != DDM_MINOR)
2274 {
2275 continue;
2276 }
2277
2278 char *pszMinorPath = di_devfs_minor_path(Minor);
2279 if (!pszMinorPath)
2280 continue;
2281
2282 char *pszDevLinkPath = NULL;
2283 di_devlink_walk(DevLink, NULL, pszMinorPath, DI_PRIMARY_LINK, &pszDevLinkPath, solarisWalkDevLink);
2284 di_devfs_path_free(pszMinorPath);
2285
2286 if (pszDevLinkPath)
2287 {
2288 char *pszSlice = solarisGetSliceFromPath(pszDevLinkPath);
2289 if ( pszSlice && !strcmp(pszSlice, "s2")
2290 && !strncmp(pszDevLinkPath, RT_STR_TUPLE("/dev/rdsk"))) /* We want only raw disks */
2291 {
2292 /*
2293 * We've got a fully qualified DVD drive. Add it to the list.
2294 */
2295 PSOLARISDVD pDrive = (PSOLARISDVD)RTMemAllocZ(sizeof(SOLARISDVD));
2296 if (RT_LIKELY(pDrive))
2297 {
2298 RTStrPrintf(pDrive->szDescription, sizeof(pDrive->szDescription), "%s %s", pszVendor, pszProduct);
2299 RTStrCopy(pDrive->szRawDiskPath, sizeof(pDrive->szRawDiskPath), pszDevLinkPath);
2300 if (*ppDrives)
2301 pDrive->pNext = *ppDrives;
2302 *ppDrives = pDrive;
2303
2304 /* We're not interested in any of the other slices, stop minor nodes traversal. */
2305 free(pszDevLinkPath);
2306 break;
2307 }
2308 }
2309 free(pszDevLinkPath);
2310 }
2311 }
2312 di_devlink_fini(&DevLink);
2313 }
2314 }
2315 }
2316 }
2317 }
2318 return DI_WALK_CONTINUE;
2319}
2320
2321/**
2322 * Solaris specific function to enumerate CD/DVD drives via the device tree.
2323 * Works on Solaris 10 as well as OpenSolaris without depending on libhal.
2324 */
2325void Host::getDVDInfoFromDevTree(std::list<ComObjPtr<Medium> > &list)
2326{
2327 PSOLARISDVD pDrives = NULL;
2328 di_node_t RootNode = di_init("/", DINFOCPYALL);
2329 if (RootNode != DI_NODE_NIL)
2330 di_walk_node(RootNode, DI_WALK_CLDFIRST, &pDrives, solarisWalkDeviceNodeForDVD);
2331
2332 di_fini(RootNode);
2333
2334 while (pDrives)
2335 {
2336 ComObjPtr<Medium> hostDVDDriveObj;
2337 hostDVDDriveObj.createObject();
2338 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(pDrives->szRawDiskPath), Bstr(pDrives->szDescription));
2339 list.push_back(hostDVDDriveObj);
2340
2341 void *pvDrive = pDrives;
2342 pDrives = pDrives->pNext;
2343 RTMemFree(pvDrive);
2344 }
2345}
2346
2347/* Solaris hosts, loading libhal at runtime */
2348
2349/**
2350 * Helper function to query the hal subsystem for information about DVD drives attached to the
2351 * system.
2352 *
2353 * @returns true if information was successfully obtained, false otherwise
2354 * @retval list drives found will be attached to this list
2355 */
2356bool Host::getDVDInfoFromHal(std::list<ComObjPtr<Medium> > &list)
2357{
2358 bool halSuccess = false;
2359 DBusError dbusError;
2360 if (!gLibHalCheckPresence())
2361 return false;
2362 gDBusErrorInit (&dbusError);
2363 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
2364 if (dbusConnection != 0)
2365 {
2366 LibHalContext *halContext = gLibHalCtxNew();
2367 if (halContext != 0)
2368 {
2369 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
2370 {
2371 if (gLibHalCtxInit(halContext, &dbusError))
2372 {
2373 int numDevices;
2374 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
2375 "storage.drive_type", "cdrom",
2376 &numDevices, &dbusError);
2377 if (halDevices != 0)
2378 {
2379 /* Hal is installed and working, so if no devices are reported, assume
2380 that there are none. */
2381 halSuccess = true;
2382 for (int i = 0; i < numDevices; i++)
2383 {
2384 char *devNode = gLibHalDeviceGetPropertyString(halContext,
2385 halDevices[i], "block.device", &dbusError);
2386#ifdef RT_OS_SOLARIS
2387 /* The CD/DVD ioctls work only for raw device nodes. */
2388 char *tmp = getfullrawname(devNode);
2389 gLibHalFreeString(devNode);
2390 devNode = tmp;
2391#endif
2392
2393 if (devNode != 0)
2394 {
2395// if (validateDevice(devNode, true))
2396// {
2397 Utf8Str description;
2398 char *vendor, *product;
2399 /* We do not check the error here, as this field may
2400 not even exist. */
2401 vendor = gLibHalDeviceGetPropertyString(halContext,
2402 halDevices[i], "info.vendor", 0);
2403 product = gLibHalDeviceGetPropertyString(halContext,
2404 halDevices[i], "info.product", &dbusError);
2405 if ((product != 0 && product[0] != 0))
2406 {
2407 if ((vendor != 0) && (vendor[0] != 0))
2408 {
2409 description = Utf8StrFmt ("%s %s",
2410 vendor, product);
2411 }
2412 else
2413 {
2414 description = product;
2415 }
2416 ComObjPtr<Medium> hostDVDDriveObj;
2417 hostDVDDriveObj.createObject();
2418 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
2419 Bstr(devNode), Bstr(description));
2420 list.push_back (hostDVDDriveObj);
2421 }
2422 else
2423 {
2424 if (product == 0)
2425 {
2426 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
2427 halDevices[i], dbusError.name, dbusError.message));
2428 gDBusErrorFree(&dbusError);
2429 }
2430 ComObjPtr<Medium> hostDVDDriveObj;
2431 hostDVDDriveObj.createObject();
2432 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
2433 Bstr(devNode));
2434 list.push_back (hostDVDDriveObj);
2435 }
2436 if (vendor != 0)
2437 {
2438 gLibHalFreeString(vendor);
2439 }
2440 if (product != 0)
2441 {
2442 gLibHalFreeString(product);
2443 }
2444// }
2445// else
2446// {
2447// LogRel(("Host::COMGETTER(DVDDrives): failed to validate the block device %s as a DVD drive\n"));
2448// }
2449#ifndef RT_OS_SOLARIS
2450 gLibHalFreeString(devNode);
2451#else
2452 free(devNode);
2453#endif
2454 }
2455 else
2456 {
2457 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
2458 halDevices[i], dbusError.name, dbusError.message));
2459 gDBusErrorFree(&dbusError);
2460 }
2461 }
2462 gLibHalFreeStringArray(halDevices);
2463 }
2464 else
2465 {
2466 LogRel(("Host::COMGETTER(DVDDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2467 gDBusErrorFree(&dbusError);
2468 }
2469 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
2470 {
2471 LogRel(("Host::COMGETTER(DVDDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2472 gDBusErrorFree(&dbusError);
2473 }
2474 }
2475 else
2476 {
2477 LogRel(("Host::COMGETTER(DVDDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2478 gDBusErrorFree(&dbusError);
2479 }
2480 gLibHalCtxFree(halContext);
2481 }
2482 else
2483 {
2484 LogRel(("Host::COMGETTER(DVDDrives): failed to set libhal connection to dbus.\n"));
2485 }
2486 }
2487 else
2488 {
2489 LogRel(("Host::COMGETTER(DVDDrives): failed to get a libhal context - out of memory?\n"));
2490 }
2491 gDBusConnectionUnref(dbusConnection);
2492 }
2493 else
2494 {
2495 LogRel(("Host::COMGETTER(DVDDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2496 gDBusErrorFree(&dbusError);
2497 }
2498 return halSuccess;
2499}
2500
2501
2502/**
2503 * Helper function to query the hal subsystem for information about floppy drives attached to the
2504 * system.
2505 *
2506 * @returns true if information was successfully obtained, false otherwise
2507 * @retval list drives found will be attached to this list
2508 */
2509bool Host::getFloppyInfoFromHal(std::list< ComObjPtr<Medium> > &list)
2510{
2511 bool halSuccess = false;
2512 DBusError dbusError;
2513 if (!gLibHalCheckPresence())
2514 return false;
2515 gDBusErrorInit (&dbusError);
2516 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
2517 if (dbusConnection != 0)
2518 {
2519 LibHalContext *halContext = gLibHalCtxNew();
2520 if (halContext != 0)
2521 {
2522 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
2523 {
2524 if (gLibHalCtxInit(halContext, &dbusError))
2525 {
2526 int numDevices;
2527 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
2528 "storage.drive_type", "floppy",
2529 &numDevices, &dbusError);
2530 if (halDevices != 0)
2531 {
2532 /* Hal is installed and working, so if no devices are reported, assume
2533 that there are none. */
2534 halSuccess = true;
2535 for (int i = 0; i < numDevices; i++)
2536 {
2537 char *driveType = gLibHalDeviceGetPropertyString(halContext,
2538 halDevices[i], "storage.drive_type", 0);
2539 if (driveType != 0)
2540 {
2541 if (strcmp(driveType, "floppy") != 0)
2542 {
2543 gLibHalFreeString(driveType);
2544 continue;
2545 }
2546 gLibHalFreeString(driveType);
2547 }
2548 else
2549 {
2550 /* An error occurred. The attribute "storage.drive_type"
2551 probably didn't exist. */
2552 continue;
2553 }
2554 char *devNode = gLibHalDeviceGetPropertyString(halContext,
2555 halDevices[i], "block.device", &dbusError);
2556 if (devNode != 0)
2557 {
2558// if (validateDevice(devNode, false))
2559// {
2560 Utf8Str description;
2561 char *vendor, *product;
2562 /* We do not check the error here, as this field may
2563 not even exist. */
2564 vendor = gLibHalDeviceGetPropertyString(halContext,
2565 halDevices[i], "info.vendor", 0);
2566 product = gLibHalDeviceGetPropertyString(halContext,
2567 halDevices[i], "info.product", &dbusError);
2568 if ((product != 0) && (product[0] != 0))
2569 {
2570 if ((vendor != 0) && (vendor[0] != 0))
2571 {
2572 description = Utf8StrFmt ("%s %s",
2573 vendor, product);
2574 }
2575 else
2576 {
2577 description = product;
2578 }
2579 ComObjPtr<Medium> hostFloppyDrive;
2580 hostFloppyDrive.createObject();
2581 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
2582 Bstr(devNode), Bstr(description));
2583 list.push_back (hostFloppyDrive);
2584 }
2585 else
2586 {
2587 if (product == 0)
2588 {
2589 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
2590 halDevices[i], dbusError.name, dbusError.message));
2591 gDBusErrorFree(&dbusError);
2592 }
2593 ComObjPtr<Medium> hostFloppyDrive;
2594 hostFloppyDrive.createObject();
2595 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
2596 Bstr(devNode));
2597 list.push_back (hostFloppyDrive);
2598 }
2599 if (vendor != 0)
2600 {
2601 gLibHalFreeString(vendor);
2602 }
2603 if (product != 0)
2604 {
2605 gLibHalFreeString(product);
2606 }
2607// }
2608// else
2609// {
2610// LogRel(("Host::COMGETTER(FloppyDrives): failed to validate the block device %s as a floppy drive\n"));
2611// }
2612 gLibHalFreeString(devNode);
2613 }
2614 else
2615 {
2616 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
2617 halDevices[i], dbusError.name, dbusError.message));
2618 gDBusErrorFree(&dbusError);
2619 }
2620 }
2621 gLibHalFreeStringArray(halDevices);
2622 }
2623 else
2624 {
2625 LogRel(("Host::COMGETTER(FloppyDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2626 gDBusErrorFree(&dbusError);
2627 }
2628 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
2629 {
2630 LogRel(("Host::COMGETTER(FloppyDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2631 gDBusErrorFree(&dbusError);
2632 }
2633 }
2634 else
2635 {
2636 LogRel(("Host::COMGETTER(FloppyDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2637 gDBusErrorFree(&dbusError);
2638 }
2639 gLibHalCtxFree(halContext);
2640 }
2641 else
2642 {
2643 LogRel(("Host::COMGETTER(FloppyDrives): failed to set libhal connection to dbus.\n"));
2644 }
2645 }
2646 else
2647 {
2648 LogRel(("Host::COMGETTER(FloppyDrives): failed to get a libhal context - out of memory?\n"));
2649 }
2650 gDBusConnectionUnref(dbusConnection);
2651 }
2652 else
2653 {
2654 LogRel(("Host::COMGETTER(FloppyDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2655 gDBusErrorFree(&dbusError);
2656 }
2657 return halSuccess;
2658}
2659#endif /* RT_OS_SOLARIS and VBOX_USE_HAL */
2660
2661/** @todo get rid of dead code below - RT_OS_SOLARIS and RT_OS_LINUX are never both set */
2662#if defined(RT_OS_SOLARIS)
2663
2664/**
2665 * Helper function to parse the given mount file and add found entries
2666 */
2667void Host::parseMountTable(char *mountTable, std::list< ComObjPtr<Medium> > &list)
2668{
2669#ifdef RT_OS_LINUX
2670 FILE *mtab = setmntent(mountTable, "r");
2671 if (mtab)
2672 {
2673 struct mntent *mntent;
2674 char *mnt_type;
2675 char *mnt_dev;
2676 char *tmp;
2677 while ((mntent = getmntent(mtab)))
2678 {
2679 mnt_type = (char*)malloc(strlen(mntent->mnt_type) + 1);
2680 mnt_dev = (char*)malloc(strlen(mntent->mnt_fsname) + 1);
2681 strcpy(mnt_type, mntent->mnt_type);
2682 strcpy(mnt_dev, mntent->mnt_fsname);
2683 // supermount fs case
2684 if (strcmp(mnt_type, "supermount") == 0)
2685 {
2686 tmp = strstr(mntent->mnt_opts, "fs=");
2687 if (tmp)
2688 {
2689 free(mnt_type);
2690 mnt_type = strdup(tmp + strlen("fs="));
2691 if (mnt_type)
2692 {
2693 tmp = strchr(mnt_type, ',');
2694 if (tmp)
2695 *tmp = '\0';
2696 }
2697 }
2698 tmp = strstr(mntent->mnt_opts, "dev=");
2699 if (tmp)
2700 {
2701 free(mnt_dev);
2702 mnt_dev = strdup(tmp + strlen("dev="));
2703 if (mnt_dev)
2704 {
2705 tmp = strchr(mnt_dev, ',');
2706 if (tmp)
2707 *tmp = '\0';
2708 }
2709 }
2710 }
2711 // use strstr here to cover things fs types like "udf,iso9660"
2712 if (strstr(mnt_type, "iso9660") == 0)
2713 {
2714 /** @todo check whether we've already got the drive in our list! */
2715 if (validateDevice(mnt_dev, true))
2716 {
2717 ComObjPtr<Medium> hostDVDDriveObj;
2718 hostDVDDriveObj.createObject();
2719 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(mnt_dev));
2720 list.push_back (hostDVDDriveObj);
2721 }
2722 }
2723 free(mnt_dev);
2724 free(mnt_type);
2725 }
2726 endmntent(mtab);
2727 }
2728#else // RT_OS_SOLARIS
2729 FILE *mntFile = fopen(mountTable, "r");
2730 if (mntFile)
2731 {
2732 struct mnttab mntTab;
2733 while (getmntent(mntFile, &mntTab) == 0)
2734 {
2735 const char *mountName = mntTab.mnt_special;
2736 const char *mountPoint = mntTab.mnt_mountp;
2737 const char *mountFSType = mntTab.mnt_fstype;
2738 if (mountName && mountPoint && mountFSType)
2739 {
2740 // skip devices we are not interested in
2741 if ((*mountName && mountName[0] == '/') && // skip 'fake' devices (like -hosts, proc, fd, swap)
2742 (*mountFSType && (strncmp(mountFSType, RT_STR_TUPLE("devfs")) != 0 && // skip devfs (i.e. /devices)
2743 strncmp(mountFSType, RT_STR_TUPLE("dev")) != 0 && // skip dev (i.e. /dev)
2744 strncmp(mountFSType, RT_STR_TUPLE("lofs")) != 0))) // skip loop-back file-system (lofs)
2745 {
2746 char *rawDevName = getfullrawname((char *)mountName);
2747 if (validateDevice(rawDevName, true))
2748 {
2749 ComObjPtr<Medium> hostDVDDriveObj;
2750 hostDVDDriveObj.createObject();
2751 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(rawDevName));
2752 list.push_back (hostDVDDriveObj);
2753 }
2754 free(rawDevName);
2755 }
2756 }
2757 }
2758
2759 fclose(mntFile);
2760 }
2761#endif
2762}
2763
2764/**
2765 * Helper function to check whether the given device node is a valid drive
2766 */
2767bool Host::validateDevice(const char *deviceNode, bool isCDROM)
2768{
2769 struct stat statInfo;
2770 bool retValue = false;
2771
2772 // sanity check
2773 if (!deviceNode)
2774 {
2775 return false;
2776 }
2777
2778 // first a simple stat() call
2779 if (stat(deviceNode, &statInfo) < 0)
2780 {
2781 return false;
2782 }
2783 else
2784 {
2785 if (isCDROM)
2786 {
2787 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2788 {
2789 int fileHandle;
2790 // now try to open the device
2791 fileHandle = open(deviceNode, O_RDONLY | O_NONBLOCK, 0);
2792 if (fileHandle >= 0)
2793 {
2794 cdrom_subchnl cdChannelInfo;
2795 cdChannelInfo.cdsc_format = CDROM_MSF;
2796 // this call will finally reveal the whole truth
2797#ifdef RT_OS_LINUX
2798 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2799 (errno == EIO) || (errno == ENOENT) ||
2800 (errno == EINVAL) || (errno == ENOMEDIUM))
2801#else
2802 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2803 (errno == EIO) || (errno == ENOENT) ||
2804 (errno == EINVAL))
2805#endif
2806 {
2807 retValue = true;
2808 }
2809 close(fileHandle);
2810 }
2811 }
2812 } else
2813 {
2814 // floppy case
2815 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2816 {
2817 /// @todo do some more testing, maybe a nice IOCTL!
2818 retValue = true;
2819 }
2820 }
2821 }
2822 return retValue;
2823}
2824#endif // RT_OS_SOLARIS
2825
2826#ifdef VBOX_WITH_USB
2827/**
2828 * Checks for the presence and status of the USB Proxy Service.
2829 * Returns S_OK when the Proxy is present and OK, VBOX_E_HOST_ERROR (as a
2830 * warning) if the proxy service is not available due to the way the host is
2831 * configured (at present, that means that usbfs and hal/DBus are not
2832 * available on a Linux host) or E_FAIL and a corresponding error message
2833 * otherwise. Intended to be used by methods that rely on the Proxy Service
2834 * availability.
2835 *
2836 * @note This method may return a warning result code. It is recommended to use
2837 * MultiError to store the return value.
2838 *
2839 * @note Locks this object for reading.
2840 */
2841HRESULT Host::checkUSBProxyService()
2842{
2843 AutoCaller autoCaller(this);
2844 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2845
2846 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2847
2848 AssertReturn(m->pUSBProxyService, E_FAIL);
2849 if (!m->pUSBProxyService->isActive())
2850 {
2851 /* disable the USB controller completely to avoid assertions if the
2852 * USB proxy service could not start. */
2853
2854 switch (m->pUSBProxyService->getLastError())
2855 {
2856 case VERR_FILE_NOT_FOUND: /** @todo what does this mean? */
2857 return setWarning(E_FAIL,
2858 tr("Could not load the Host USB Proxy Service (VERR_FILE_NOT_FOUND). The service might not be installed on the host computer"));
2859 case VERR_VUSB_USB_DEVICE_PERMISSION:
2860 return setWarning(E_FAIL,
2861 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"));
2862 case VERR_VUSB_USBFS_PERMISSION:
2863 return setWarning(E_FAIL,
2864 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"));
2865 case VINF_SUCCESS:
2866 return setWarning(E_FAIL,
2867 tr("The USB Proxy Service has not yet been ported to this host"));
2868 default:
2869 return setWarning (E_FAIL, "%s: %Rrc",
2870 tr ("Could not load the Host USB Proxy service"),
2871 m->pUSBProxyService->getLastError());
2872 }
2873 }
2874
2875 return S_OK;
2876}
2877#endif /* VBOX_WITH_USB */
2878
2879HRESULT Host::updateNetIfList()
2880{
2881#ifdef VBOX_WITH_HOSTNETIF_API
2882 AssertReturn(AutoCaller(this).state() == InInit ||
2883 isWriteLockOnCurrentThread(), E_FAIL);
2884
2885 HostNetworkInterfaceList list, listCopy;
2886 int rc = NetIfList(list);
2887 if (rc)
2888 {
2889 Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
2890 return E_FAIL;
2891 }
2892 AssertReturn(m->pParent, E_FAIL);
2893 /* Make a copy as the original may be partially destroyed later. */
2894 listCopy = list;
2895 HostNetworkInterfaceList::iterator itOld, itNew;
2896 PerformanceCollector *aCollector = m->pParent->performanceCollector();
2897 for (itOld = m->llNetIfs.begin(); itOld != m->llNetIfs.end(); ++itOld)
2898 {
2899 bool fGone = true;
2900 Bstr nameOld;
2901 (*itOld)->COMGETTER(Name) (nameOld.asOutParam());
2902 for (itNew = listCopy.begin(); itNew != listCopy.end(); ++itNew)
2903 {
2904 Bstr nameNew;
2905 (*itNew)->COMGETTER(Name) (nameNew.asOutParam());
2906 if (nameNew == nameOld)
2907 {
2908 fGone = false;
2909 listCopy.erase(itNew);
2910 break;
2911 }
2912 }
2913 if (fGone)
2914 (*itOld)->unregisterMetrics(aCollector, this);
2915 }
2916 /*
2917 * Need to set the references to VirtualBox object in all interface objects
2918 * (see @bugref{6439}).
2919 */
2920 for (itNew = list.begin(); itNew != list.end(); ++itNew)
2921 (*itNew)->setVirtualBox(m->pParent);
2922 /* At this point listCopy will contain newly discovered interfaces only. */
2923 for (itNew = listCopy.begin(); itNew != listCopy.end(); ++itNew)
2924 {
2925 HostNetworkInterfaceType_T t;
2926 HRESULT hr = (*itNew)->COMGETTER(InterfaceType)(&t);
2927 if (FAILED(hr))
2928 {
2929 Bstr n;
2930 (*itNew)->COMGETTER(Name) (n.asOutParam());
2931 LogRel(("Host::updateNetIfList: failed to get interface type for %ls\n", n.raw()));
2932 }
2933 else if (t == HostNetworkInterfaceType_Bridged)
2934 (*itNew)->registerMetrics(aCollector, this);
2935 }
2936 m->llNetIfs = list;
2937 return S_OK;
2938#else
2939 return E_NOTIMPL;
2940#endif
2941}
2942
2943#ifdef VBOX_WITH_RESOURCE_USAGE_API
2944
2945void Host::registerDiskMetrics(PerformanceCollector *aCollector)
2946{
2947 pm::CollectorHAL *hal = aCollector->getHAL();
2948 /* Create sub metrics */
2949 Utf8StrFmt fsNameBase("FS/{%s}/Usage", "/");
2950 //Utf8StrFmt fsNameBase("Filesystem/[root]/Usage");
2951 pm::SubMetric *fsRootUsageTotal = new pm::SubMetric(fsNameBase + "/Total",
2952 "Root file system size.");
2953 pm::SubMetric *fsRootUsageUsed = new pm::SubMetric(fsNameBase + "/Used",
2954 "Root file system space currently occupied.");
2955 pm::SubMetric *fsRootUsageFree = new pm::SubMetric(fsNameBase + "/Free",
2956 "Root file system space currently empty.");
2957
2958 pm::BaseMetric *fsRootUsage = new pm::HostFilesystemUsage(hal, this,
2959 fsNameBase, "/",
2960 fsRootUsageTotal,
2961 fsRootUsageUsed,
2962 fsRootUsageFree);
2963 aCollector->registerBaseMetric (fsRootUsage);
2964
2965 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageTotal, 0));
2966 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageTotal,
2967 new pm::AggregateAvg()));
2968 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageTotal,
2969 new pm::AggregateMin()));
2970 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageTotal,
2971 new pm::AggregateMax()));
2972
2973 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageUsed, 0));
2974 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageUsed,
2975 new pm::AggregateAvg()));
2976 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageUsed,
2977 new pm::AggregateMin()));
2978 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageUsed,
2979 new pm::AggregateMax()));
2980
2981 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageFree, 0));
2982 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageFree,
2983 new pm::AggregateAvg()));
2984 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageFree,
2985 new pm::AggregateMin()));
2986 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageFree,
2987 new pm::AggregateMax()));
2988
2989 /* For now we are concerned with the root file system only. */
2990 pm::DiskList disksUsage, disksLoad;
2991 int rc = hal->getDiskListByFs("/", disksUsage, disksLoad);
2992 if (RT_FAILURE(rc))
2993 return;
2994 pm::DiskList::iterator it;
2995 for (it = disksLoad.begin(); it != disksLoad.end(); ++it)
2996 {
2997 Utf8StrFmt strName("Disk/%s", it->c_str());
2998 pm::SubMetric *fsLoadUtil = new pm::SubMetric(strName + "/Load/Util",
2999 "Percentage of time disk was busy serving I/O requests.");
3000 pm::BaseMetric *fsLoad = new pm::HostDiskLoadRaw(hal, this, strName + "/Load",
3001 *it, fsLoadUtil);
3002 aCollector->registerBaseMetric (fsLoad);
3003
3004 aCollector->registerMetric(new pm::Metric(fsLoad, fsLoadUtil, 0));
3005 aCollector->registerMetric(new pm::Metric(fsLoad, fsLoadUtil,
3006 new pm::AggregateAvg()));
3007 aCollector->registerMetric(new pm::Metric(fsLoad, fsLoadUtil,
3008 new pm::AggregateMin()));
3009 aCollector->registerMetric(new pm::Metric(fsLoad, fsLoadUtil,
3010 new pm::AggregateMax()));
3011 }
3012 for (it = disksUsage.begin(); it != disksUsage.end(); ++it)
3013 {
3014 Utf8StrFmt strName("Disk/%s", it->c_str());
3015 pm::SubMetric *fsUsageTotal = new pm::SubMetric(strName + "/Usage/Total",
3016 "Disk size.");
3017 pm::BaseMetric *fsUsage = new pm::HostDiskUsage(hal, this, strName + "/Usage",
3018 *it, fsUsageTotal);
3019 aCollector->registerBaseMetric (fsUsage);
3020
3021 aCollector->registerMetric(new pm::Metric(fsUsage, fsUsageTotal, 0));
3022 aCollector->registerMetric(new pm::Metric(fsUsage, fsUsageTotal,
3023 new pm::AggregateAvg()));
3024 aCollector->registerMetric(new pm::Metric(fsUsage, fsUsageTotal,
3025 new pm::AggregateMin()));
3026 aCollector->registerMetric(new pm::Metric(fsUsage, fsUsageTotal,
3027 new pm::AggregateMax()));
3028 }
3029}
3030
3031void Host::registerMetrics(PerformanceCollector *aCollector)
3032{
3033 pm::CollectorHAL *hal = aCollector->getHAL();
3034 /* Create sub metrics */
3035 pm::SubMetric *cpuLoadUser = new pm::SubMetric("CPU/Load/User",
3036 "Percentage of processor time spent in user mode.");
3037 pm::SubMetric *cpuLoadKernel = new pm::SubMetric("CPU/Load/Kernel",
3038 "Percentage of processor time spent in kernel mode.");
3039 pm::SubMetric *cpuLoadIdle = new pm::SubMetric("CPU/Load/Idle",
3040 "Percentage of processor time spent idling.");
3041 pm::SubMetric *cpuMhzSM = new pm::SubMetric("CPU/MHz",
3042 "Average of current frequency of all processors.");
3043 pm::SubMetric *ramUsageTotal = new pm::SubMetric("RAM/Usage/Total",
3044 "Total physical memory installed.");
3045 pm::SubMetric *ramUsageUsed = new pm::SubMetric("RAM/Usage/Used",
3046 "Physical memory currently occupied.");
3047 pm::SubMetric *ramUsageFree = new pm::SubMetric("RAM/Usage/Free",
3048 "Physical memory currently available to applications.");
3049 pm::SubMetric *ramVMMUsed = new pm::SubMetric("RAM/VMM/Used",
3050 "Total physical memory used by the hypervisor.");
3051 pm::SubMetric *ramVMMFree = new pm::SubMetric("RAM/VMM/Free",
3052 "Total physical memory free inside the hypervisor.");
3053 pm::SubMetric *ramVMMBallooned = new pm::SubMetric("RAM/VMM/Ballooned",
3054 "Total physical memory ballooned by the hypervisor.");
3055 pm::SubMetric *ramVMMShared = new pm::SubMetric("RAM/VMM/Shared",
3056 "Total physical memory shared between VMs.");
3057
3058
3059 /* Create and register base metrics */
3060 pm::BaseMetric *cpuLoad = new pm::HostCpuLoadRaw(hal, this, cpuLoadUser, cpuLoadKernel,
3061 cpuLoadIdle);
3062 aCollector->registerBaseMetric (cpuLoad);
3063 pm::BaseMetric *cpuMhz = new pm::HostCpuMhz(hal, this, cpuMhzSM);
3064 aCollector->registerBaseMetric (cpuMhz);
3065 pm::BaseMetric *ramUsage = new pm::HostRamUsage(hal, this,
3066 ramUsageTotal,
3067 ramUsageUsed,
3068 ramUsageFree);
3069 aCollector->registerBaseMetric (ramUsage);
3070 pm::BaseMetric *ramVmm = new pm::HostRamVmm(aCollector->getGuestManager(), this,
3071 ramVMMUsed,
3072 ramVMMFree,
3073 ramVMMBallooned,
3074 ramVMMShared);
3075 aCollector->registerBaseMetric (ramVmm);
3076
3077 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser, 0));
3078 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
3079 new pm::AggregateAvg()));
3080 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
3081 new pm::AggregateMin()));
3082 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
3083 new pm::AggregateMax()));
3084
3085 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel, 0));
3086 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
3087 new pm::AggregateAvg()));
3088 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
3089 new pm::AggregateMin()));
3090 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
3091 new pm::AggregateMax()));
3092
3093 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle, 0));
3094 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
3095 new pm::AggregateAvg()));
3096 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
3097 new pm::AggregateMin()));
3098 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
3099 new pm::AggregateMax()));
3100
3101 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM, 0));
3102 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
3103 new pm::AggregateAvg()));
3104 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
3105 new pm::AggregateMin()));
3106 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
3107 new pm::AggregateMax()));
3108
3109 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal, 0));
3110 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
3111 new pm::AggregateAvg()));
3112 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
3113 new pm::AggregateMin()));
3114 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
3115 new pm::AggregateMax()));
3116
3117 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed, 0));
3118 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
3119 new pm::AggregateAvg()));
3120 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
3121 new pm::AggregateMin()));
3122 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
3123 new pm::AggregateMax()));
3124
3125 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree, 0));
3126 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
3127 new pm::AggregateAvg()));
3128 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
3129 new pm::AggregateMin()));
3130 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
3131 new pm::AggregateMax()));
3132
3133 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed, 0));
3134 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
3135 new pm::AggregateAvg()));
3136 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
3137 new pm::AggregateMin()));
3138 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
3139 new pm::AggregateMax()));
3140
3141 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree, 0));
3142 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
3143 new pm::AggregateAvg()));
3144 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
3145 new pm::AggregateMin()));
3146 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
3147 new pm::AggregateMax()));
3148
3149 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned, 0));
3150 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
3151 new pm::AggregateAvg()));
3152 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
3153 new pm::AggregateMin()));
3154 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
3155 new pm::AggregateMax()));
3156
3157 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared, 0));
3158 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
3159 new pm::AggregateAvg()));
3160 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
3161 new pm::AggregateMin()));
3162 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
3163 new pm::AggregateMax()));
3164 registerDiskMetrics(aCollector);
3165}
3166
3167void Host::unregisterMetrics (PerformanceCollector *aCollector)
3168{
3169 aCollector->unregisterMetricsFor(this);
3170 aCollector->unregisterBaseMetricsFor(this);
3171}
3172
3173
3174/* static */
3175void Host::generateMACAddress(Utf8Str &mac)
3176{
3177 /*
3178 * Our strategy is as follows: the first three bytes are our fixed
3179 * vendor ID (080027). The remaining 3 bytes will be taken from the
3180 * start of a GUID. This is a fairly safe algorithm.
3181 */
3182 Guid guid;
3183 guid.create();
3184 mac = Utf8StrFmt("080027%02X%02X%02X",
3185 guid.raw()->au8[0], guid.raw()->au8[1], guid.raw()->au8[2]);
3186}
3187
3188#endif /* VBOX_WITH_RESOURCE_USAGE_API */
3189
3190/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

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