VirtualBox

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

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

Main/HostDnsService: fixed object deletion and coding style

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

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