VirtualBox

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

最後變更 在這個檔案從80824是 80797,由 vboxsync 提交於 6 年 前

Main/Host: adapt condition for nested virtualization, including VT-x if unrestricted execution is available

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

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