VirtualBox

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

Last change on this file since 45434 was 45367, checked in by vboxsync, 12 years ago

Main: a couple of whitespace fixes

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