VirtualBox

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

Last change on this file since 56474 was 55967, checked in by vboxsync, 10 years ago

Main/Host: Close the support driver as soon as we no longer need it. Not worth keeping it open all the time. Allows reloading the driver while VBoxSVC is running, and avoids quirks during debugging of VBoxSVC: it is quite normal that the Host object is created several times, which means that multiple SUPR3InitEx calls are made.

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

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