VirtualBox

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

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

Bad commit, reverted with following changeset

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