VirtualBox

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

Last change on this file since 67954 was 66581, checked in by vboxsync, 7 years ago

VMM: Nested Hw.virt: Implemented various SVM intercepts in IEM, addressed some todos.

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