VirtualBox

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

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

6813 stage 7 VirtualBoxImpl.cpp etc

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

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