VirtualBox

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

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

Main: warnings

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