VirtualBox

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

Last change on this file since 81305 was 81305, checked in by vboxsync, 5 years ago

Main/HostImpl: Updated CPU features with nested VT-x conditions. Joined up the duplicate init and query-time into a helper function. (untested). bugref:9180

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

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