VirtualBox

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

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

VBoxManage,Main: VideoCaptureDevice -> VideoInputDevice

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