VirtualBox

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

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

Main,FE,doc/VBoxManage+Host+SystemProperties+manual: bugref:7983: Move update check from GUI to API, add more data

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