VirtualBox

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

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

NetAdp/Win: (bugref:9409) Work around host-only adapter naming issue after Windows upgrade.

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