VirtualBox

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

Last change on this file since 55747 was 55616, checked in by vboxsync, 10 years ago

Main/Linux/HostPower: add DBus-based host suspend and resume notifications, only if VBOX_WITH_DBUS defined.

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