VirtualBox

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

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

6813 stage 2 - Use the server side API wrapper code..

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

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