VirtualBox

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

Last change on this file since 81682 was 81682, checked in by vboxsync, 6 years ago

Main/Console+ConsoleVRDPServer+ApplianceExport+Host+Machine+USBDeviceFilters: fix missing RT_NOREF(...) if VBOX_WITH_USB is undefined

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

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