VirtualBox

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

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

Main/Host: make sure that all relevant objects are uninitialized when the Host object is uninitialized, otherwise there will be races (especially when API clients crash) between the VirtualBox object shutdown and the other objects which might get cleaned up a little later, resulting in "pure virtual function" calls due to using the vtable of the VirtualBox object after it was freed

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

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