VirtualBox

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

Last change on this file since 47053 was 47022, checked in by vboxsync, 12 years ago

Main: typo: strcmp -> strcpy.

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

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