VirtualBox

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

Last change on this file since 76789 was 76592, checked in by vboxsync, 6 years ago

Main: Don't use Logging.h.

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