VirtualBox

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

Last change on this file since 49764 was 49764, checked in by vboxsync, 11 years ago

Main/Host: actually return the progress object

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

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