VirtualBox

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

Last change on this file since 60067 was 60067, checked in by vboxsync, 9 years ago

Main: Add API to IHost for adding and removing USB device sources in addition to the default host one (only USB/IP backend supported so far which will be used in the future for automatic USB testing). Add support for it in VBoxManage

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