VirtualBox

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

Last change on this file since 85596 was 85266, checked in by vboxsync, 4 years ago

Main/HostImpl.cpp: Some cleanups around NetIfCreateHostOnlyNetworkInterface. bugref:9790

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

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