VirtualBox

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

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

Main: Eradicate the use of BSTR in regular API code, there were leaks in almost every occurrence. Also do some Bstr->Utf8Str shuffling to reduce the number of conversions.

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