VirtualBox

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

Last change on this file since 72288 was 70918, checked in by vboxsync, 7 years ago

VMM: NEM kick off.

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

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