VirtualBox

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

Last change on this file since 43185 was 42664, checked in by vboxsync, 12 years ago

Allow Main to detect VIA VT-x support.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 102.9 KB
Line 
1/* $Id: HostImpl.cpp 42664 2012-08-07 14:34:48Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation: Host
4 */
5
6/*
7 * Copyright (C) 2004-2012 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 __STDC_LIMIT_MACROS
19#define __STDC_CONSTANT_MACROS
20
21// for some reason Windows burns in sdk\...\winsock.h if this isn't included first
22#include "VBox/com/ptr.h"
23
24#include "HostImpl.h"
25
26#ifdef VBOX_WITH_USB
27# include "HostUSBDeviceImpl.h"
28# include "USBDeviceFilterImpl.h"
29# include "USBProxyService.h"
30#endif // VBOX_WITH_USB
31
32#include "HostNetworkInterfaceImpl.h"
33#include "MachineImpl.h"
34#include "AutoCaller.h"
35#include "Logging.h"
36#include "Performance.h"
37
38#include "MediumImpl.h"
39#include "HostPower.h"
40
41#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
42# include <HostHardwareLinux.h>
43#endif
44
45#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
46# include <set>
47#endif
48
49#ifdef VBOX_WITH_RESOURCE_USAGE_API
50# include "PerformanceImpl.h"
51#endif /* VBOX_WITH_RESOURCE_USAGE_API */
52
53#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
54# include <VBox/VBoxNetCfg-win.h>
55#endif /* #if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT) */
56
57#ifdef RT_OS_LINUX
58# include <sys/ioctl.h>
59# include <errno.h>
60# include <net/if.h>
61# include <net/if_arp.h>
62#endif /* RT_OS_LINUX */
63
64#ifdef RT_OS_SOLARIS
65# include <fcntl.h>
66# include <unistd.h>
67# include <stropts.h>
68# include <errno.h>
69# include <limits.h>
70# include <stdio.h>
71# include <libdevinfo.h>
72# include <sys/mkdev.h>
73# include <sys/scsi/generic/inquiry.h>
74# include <net/if.h>
75# include <sys/socket.h>
76# include <sys/sockio.h>
77# include <net/if_arp.h>
78# include <net/if.h>
79# include <sys/types.h>
80# include <sys/stat.h>
81# include <sys/cdio.h>
82# include <sys/dkio.h>
83# include <sys/mnttab.h>
84# include <sys/mntent.h>
85/* Dynamic loading of libhal on Solaris hosts */
86# ifdef VBOX_USE_LIBHAL
87# include "vbox-libhal.h"
88extern "C" char *getfullrawname(char *);
89# endif
90# include "solaris/DynLoadLibSolaris.h"
91
92/**
93 * Solaris DVD drive list as returned by getDVDInfoFromDevTree().
94 */
95typedef struct SOLARISDVD
96{
97 struct SOLARISDVD *pNext;
98 char szDescription[512];
99 char szRawDiskPath[PATH_MAX];
100} SOLARISDVD;
101/** Pointer to a Solaris DVD descriptor. */
102typedef SOLARISDVD *PSOLARISDVD;
103
104#endif /* RT_OS_SOLARIS */
105
106#ifdef RT_OS_WINDOWS
107# define _WIN32_DCOM
108# include <windows.h>
109# include <shellapi.h>
110# define INITGUID
111# include <guiddef.h>
112# include <devguid.h>
113# include <objbase.h>
114//# include <setupapi.h>
115# include <shlobj.h>
116# include <cfgmgr32.h>
117
118#endif /* RT_OS_WINDOWS */
119
120#ifdef RT_OS_DARWIN
121# include "darwin/iokit.h"
122#endif
123
124#ifdef VBOX_WITH_CROGL
125#include <VBox/VBoxOGLTest.h>
126#endif /* VBOX_WITH_CROGL */
127
128#include <iprt/asm-amd64-x86.h>
129#include <iprt/string.h>
130#include <iprt/mp.h>
131#include <iprt/time.h>
132#include <iprt/param.h>
133#include <iprt/env.h>
134#include <iprt/mem.h>
135#include <iprt/system.h>
136#ifdef RT_OS_SOLARIS
137# include <iprt/path.h>
138# include <iprt/ctype.h>
139#endif
140#ifdef VBOX_WITH_HOSTNETIF_API
141# include "netif.h"
142#endif
143
144/* XXX Solaris: definitions in /usr/include/sys/regset.h clash with hwacc_svm.h */
145#undef DS
146#undef ES
147#undef CS
148#undef SS
149#undef FS
150#undef GS
151
152#include <VBox/usb.h>
153#include <VBox/vmm/hwacc_svm.h>
154#include <VBox/err.h>
155#include <VBox/settings.h>
156#include <VBox/sup.h>
157#include <iprt/x86.h>
158
159#include "VBox/com/MultiResult.h"
160
161#include <stdio.h>
162
163#include <algorithm>
164
165////////////////////////////////////////////////////////////////////////////////
166//
167// Host private data definition
168//
169////////////////////////////////////////////////////////////////////////////////
170
171struct Host::Data
172{
173 Data()
174 :
175 fDVDDrivesListBuilt(false),
176 fFloppyDrivesListBuilt(false)
177 {};
178
179 VirtualBox *pParent;
180
181#ifdef VBOX_WITH_USB
182 USBDeviceFilterList llChildren; // all USB device filters
183 USBDeviceFilterList llUSBDeviceFilters; // USB device filters in use by the USB proxy service
184
185 /** Pointer to the USBProxyService object. */
186 USBProxyService *pUSBProxyService;
187#endif /* VBOX_WITH_USB */
188
189 // list of host drives; lazily created by getDVDDrives() and getFloppyDrives(),
190 // and protected by the medium tree lock handle (including the bools).
191 MediaList llDVDDrives,
192 llFloppyDrives;
193 bool fDVDDrivesListBuilt,
194 fFloppyDrivesListBuilt;
195
196#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
197 /** Object with information about host drives */
198 VBoxMainDriveInfo hostDrives;
199#endif
200 /* Features that can be queried with GetProcessorFeature */
201 BOOL fVTSupported,
202 fLongModeSupported,
203 fPAESupported,
204 fNestedPagingSupported;
205
206 /* 3D hardware acceleration supported? */
207 BOOL f3DAccelerationSupported;
208
209 HostPowerService *pHostPowerService;
210};
211
212
213////////////////////////////////////////////////////////////////////////////////
214//
215// Constructor / destructor
216//
217////////////////////////////////////////////////////////////////////////////////
218
219HRESULT Host::FinalConstruct()
220{
221 return BaseFinalConstruct();
222}
223
224void Host::FinalRelease()
225{
226 uninit();
227 BaseFinalRelease();
228}
229
230/**
231 * Initializes the host object.
232 *
233 * @param aParent VirtualBox parent object.
234 */
235HRESULT Host::init(VirtualBox *aParent)
236{
237 HRESULT hrc;
238 LogFlowThisFunc(("aParent=%p\n", aParent));
239
240 /* Enclose the state transition NotReady->InInit->Ready */
241 AutoInitSpan autoInitSpan(this);
242 AssertReturn(autoInitSpan.isOk(), E_FAIL);
243
244 m = new Data();
245
246 m->pParent = aParent;
247
248#ifdef VBOX_WITH_USB
249 /*
250 * Create and initialize the USB Proxy Service.
251 */
252# if defined (RT_OS_DARWIN)
253 m->pUSBProxyService = new USBProxyServiceDarwin(this);
254# elif defined (RT_OS_LINUX)
255 m->pUSBProxyService = new USBProxyServiceLinux(this);
256# elif defined (RT_OS_OS2)
257 m->pUSBProxyService = new USBProxyServiceOs2(this);
258# elif defined (RT_OS_SOLARIS)
259 m->pUSBProxyService = new USBProxyServiceSolaris(this);
260# elif defined (RT_OS_WINDOWS)
261 m->pUSBProxyService = new USBProxyServiceWindows(this);
262# elif defined (RT_OS_FREEBSD)
263 m->pUSBProxyService = new USBProxyServiceFreeBSD(this);
264# else
265 m->pUSBProxyService = new USBProxyService(this);
266# endif
267 hrc = m->pUSBProxyService->init();
268 AssertComRCReturn(hrc, hrc);
269#endif /* VBOX_WITH_USB */
270
271#ifdef VBOX_WITH_RESOURCE_USAGE_API
272 registerMetrics(aParent->performanceCollector());
273#endif /* VBOX_WITH_RESOURCE_USAGE_API */
274
275#if defined (RT_OS_WINDOWS)
276 m->pHostPowerService = new HostPowerServiceWin(m->pParent);
277#elif defined (RT_OS_DARWIN)
278 m->pHostPowerService = new HostPowerServiceDarwin(m->pParent);
279#else
280 m->pHostPowerService = new HostPowerService(m->pParent);
281#endif
282
283 /* Cache the features reported by GetProcessorFeature. */
284 m->fVTSupported = false;
285 m->fLongModeSupported = false;
286 m->fPAESupported = false;
287 m->fNestedPagingSupported = false;
288
289 if (ASMHasCpuId())
290 {
291 uint32_t u32FeaturesECX;
292 uint32_t u32Dummy;
293 uint32_t u32FeaturesEDX;
294 uint32_t u32VendorEBX, u32VendorECX, u32VendorEDX, u32ExtFeatureEDX, u32ExtFeatureECX;
295
296 ASMCpuId(0, &u32Dummy, &u32VendorEBX, &u32VendorECX, &u32VendorEDX);
297 ASMCpuId(1, &u32Dummy, &u32Dummy, &u32FeaturesECX, &u32FeaturesEDX);
298 /* Query Extended features. */
299 ASMCpuId(0x80000001, &u32Dummy, &u32Dummy, &u32ExtFeatureECX, &u32ExtFeatureEDX);
300
301 m->fLongModeSupported = !!(u32ExtFeatureEDX & X86_CPUID_EXT_FEATURE_EDX_LONG_MODE);
302 m->fPAESupported = !!(u32FeaturesEDX & X86_CPUID_FEATURE_EDX_PAE);
303
304 if ( u32VendorEBX == X86_CPUID_VENDOR_INTEL_EBX
305 && u32VendorECX == X86_CPUID_VENDOR_INTEL_ECX
306 && u32VendorEDX == X86_CPUID_VENDOR_INTEL_EDX
307 )
308 {
309 /* Intel. */
310 if ( (u32FeaturesECX & X86_CPUID_FEATURE_ECX_VMX)
311 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR)
312 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR)
313 )
314 {
315 int rc = SUPR3QueryVTxSupported();
316 if (RT_SUCCESS(rc))
317 m->fVTSupported = true;
318 }
319 }
320 else
321 if ( u32VendorEBX == X86_CPUID_VENDOR_AMD_EBX
322 && u32VendorECX == X86_CPUID_VENDOR_AMD_ECX
323 && u32VendorEDX == X86_CPUID_VENDOR_AMD_EDX
324 )
325 {
326 /* AMD. */
327 if ( (u32ExtFeatureECX & X86_CPUID_AMD_FEATURE_ECX_SVM)
328 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR)
329 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR)
330 )
331 {
332 uint32_t u32SVMFeatureEDX;
333
334 m->fVTSupported = true;
335
336 /* Query AMD features. */
337 ASMCpuId(0x8000000A, &u32Dummy, &u32Dummy, &u32Dummy, &u32SVMFeatureEDX);
338 if (u32SVMFeatureEDX & AMD_CPUID_SVM_FEATURE_EDX_NESTED_PAGING)
339 m->fNestedPagingSupported = true;
340 }
341 }
342 else
343 if ( u32VendorEBX == X86_CPUID_VENDOR_VIA_EBX
344 && u32VendorECX == X86_CPUID_VENDOR_VIA_ECX
345 && u32VendorEDX == X86_CPUID_VENDOR_VIA_EDX
346 )
347 {
348 /* VIA. */
349 if ( (u32FeaturesECX & X86_CPUID_FEATURE_ECX_VMX)
350 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR)
351 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR)
352 )
353 {
354 int rc = SUPR3QueryVTxSupported();
355 if (RT_SUCCESS(rc))
356 m->fVTSupported = true;
357 }
358 }
359 }
360
361#if 0 /* needs testing */
362 if (m->fVTSupported)
363 {
364 uint32_t u32Caps = 0;
365
366 int rc = SUPR3QueryVTCaps(&u32Caps);
367 if (RT_SUCCESS(rc))
368 {
369 if (u32Caps & SUPVTCAPS_NESTED_PAGING)
370 m->fNestedPagingSupported = true;
371 }
372 /* else @todo; report BIOS trouble in some way. */
373 }
374#endif
375
376 /* Test for 3D hardware acceleration support */
377 m->f3DAccelerationSupported = false;
378
379#ifdef VBOX_WITH_CROGL
380 m->f3DAccelerationSupported = VBoxOglIs3DAccelerationSupported();
381#endif /* VBOX_WITH_CROGL */
382
383#if defined (RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
384 /* Extract the list of configured host-only interfaces */
385 std::set<Utf8Str> aConfiguredNames;
386 SafeArray<BSTR> aGlobalExtraDataKeys;
387 hrc = aParent->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
388 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
389 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); ++i)
390 {
391 Utf8Str strKey = aGlobalExtraDataKeys[i];
392
393 if (!strKey.startsWith("HostOnly/vboxnet"))
394 continue;
395
396 size_t pos = strKey.find("/", sizeof("HostOnly/vboxnet"));
397 if (pos != Utf8Str::npos)
398 aConfiguredNames.insert(strKey.substr(sizeof("HostOnly"),
399 pos - sizeof("HostOnly")));
400 }
401
402 for (std::set<Utf8Str>::const_iterator it = aConfiguredNames.begin();
403 it != aConfiguredNames.end();
404 ++it)
405 {
406 ComPtr<IHostNetworkInterface> hif;
407 ComPtr<IProgress> progress;
408
409 int r = NetIfCreateHostOnlyNetworkInterface(m->pParent,
410 hif.asOutParam(),
411 progress.asOutParam(),
412 it->c_str());
413 if (RT_FAILURE(r))
414 LogRel(("failed to create %s, error (0x%x)\n", it->c_str(), r));
415 }
416
417#endif /* defined (RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) */
418
419 /* Confirm a successful initialization */
420 autoInitSpan.setSucceeded();
421
422 return S_OK;
423}
424
425/**
426 * Uninitializes the host object and sets the ready flag to FALSE.
427 * Called either from FinalRelease() or by the parent when it gets destroyed.
428 */
429void Host::uninit()
430{
431 LogFlowThisFunc(("\n"));
432
433 /* Enclose the state transition Ready->InUninit->NotReady */
434 AutoUninitSpan autoUninitSpan(this);
435 if (autoUninitSpan.uninitDone())
436 return;
437
438#ifdef VBOX_WITH_RESOURCE_USAGE_API
439 unregisterMetrics (m->pParent->performanceCollector());
440#endif /* VBOX_WITH_RESOURCE_USAGE_API */
441
442#ifdef VBOX_WITH_USB
443 /* wait for USB proxy service to terminate before we uninit all USB
444 * devices */
445 LogFlowThisFunc(("Stopping USB proxy service...\n"));
446 delete m->pUSBProxyService;
447 m->pUSBProxyService = NULL;
448 LogFlowThisFunc(("Done stopping USB proxy service.\n"));
449#endif
450
451 delete m->pHostPowerService;
452
453#ifdef VBOX_WITH_USB
454 /* uninit all USB device filters still referenced by clients
455 * Note! HostUSBDeviceFilter::uninit() will modify llChildren. */
456 while (!m->llChildren.empty())
457 {
458 ComObjPtr<HostUSBDeviceFilter> &pChild = m->llChildren.front();
459 pChild->uninit();
460 }
461
462 m->llUSBDeviceFilters.clear();
463#endif
464
465 delete m;
466 m = NULL;
467}
468
469////////////////////////////////////////////////////////////////////////////////
470//
471// ISnapshot public methods
472//
473////////////////////////////////////////////////////////////////////////////////
474
475/**
476 * Returns a list of host DVD drives.
477 *
478 * @returns COM status code
479 * @param drives address of result pointer
480 */
481STDMETHODIMP Host::COMGETTER(DVDDrives)(ComSafeArrayOut(IMedium *, aDrives))
482{
483 CheckComArgOutSafeArrayPointerValid(aDrives);
484
485 AutoCaller autoCaller(this);
486 if (FAILED(autoCaller.rc())) return autoCaller.rc();
487
488 AutoWriteLock alock(m->pParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
489
490 MediaList *pList;
491 HRESULT rc = getDrives(DeviceType_DVD, true /* fRefresh */, pList);
492 if (SUCCEEDED(rc))
493 {
494 SafeIfaceArray<IMedium> array(*pList);
495 array.detachTo(ComSafeArrayOutArg(aDrives));
496 }
497
498 return rc;
499}
500
501/**
502 * Returns a list of host floppy drives.
503 *
504 * @returns COM status code
505 * @param drives address of result pointer
506 */
507STDMETHODIMP Host::COMGETTER(FloppyDrives)(ComSafeArrayOut(IMedium *, aDrives))
508{
509 CheckComArgOutPointerValid(aDrives);
510
511 AutoCaller autoCaller(this);
512 if (FAILED(autoCaller.rc())) return autoCaller.rc();
513
514 AutoWriteLock alock(m->pParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
515
516 MediaList *pList;
517 HRESULT rc = getDrives(DeviceType_Floppy, true /* fRefresh */, pList);
518 if (SUCCEEDED(rc))
519 {
520 SafeIfaceArray<IMedium> collection(*pList);
521 collection.detachTo(ComSafeArrayOutArg(aDrives));
522 }
523
524 return rc;
525}
526
527
528#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
529# define VBOX_APP_NAME L"VirtualBox"
530
531static int vboxNetWinAddComponent(std::list< ComObjPtr<HostNetworkInterface> > *pPist,
532 INetCfgComponent *pncc)
533{
534 LPWSTR lpszName;
535 GUID IfGuid;
536 HRESULT hr;
537 int rc = VERR_GENERAL_FAILURE;
538
539 hr = pncc->GetDisplayName( &lpszName );
540 Assert(hr == S_OK);
541 if (hr == S_OK)
542 {
543 Bstr name((CBSTR)lpszName);
544
545 hr = pncc->GetInstanceGuid(&IfGuid);
546 Assert(hr == S_OK);
547 if (hr == S_OK)
548 {
549 /* create a new object and add it to the list */
550 ComObjPtr<HostNetworkInterface> iface;
551 iface.createObject();
552 /* remove the curly bracket at the end */
553 if (SUCCEEDED(iface->init (name, name, Guid (IfGuid), HostNetworkInterfaceType_Bridged)))
554 {
555// iface->setVirtualBox(m->pParent);
556 pPist->push_back(iface);
557 rc = VINF_SUCCESS;
558 }
559 else
560 {
561 Assert(0);
562 }
563 }
564 CoTaskMemFree(lpszName);
565 }
566
567 return rc;
568}
569#endif /* defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT) */
570
571/**
572 * Returns a list of host network interfaces.
573 *
574 * @returns COM status code
575 * @param drives address of result pointer
576 */
577STDMETHODIMP Host::COMGETTER(NetworkInterfaces)(ComSafeArrayOut(IHostNetworkInterface*, aNetworkInterfaces))
578{
579#if defined(RT_OS_WINDOWS) || defined(VBOX_WITH_NETFLT) /*|| defined(RT_OS_OS2)*/
580 if (ComSafeArrayOutIsNull(aNetworkInterfaces))
581 return E_POINTER;
582
583 AutoCaller autoCaller(this);
584 if (FAILED(autoCaller.rc())) return autoCaller.rc();
585
586 std::list<ComObjPtr<HostNetworkInterface> > list;
587
588# ifdef VBOX_WITH_HOSTNETIF_API
589 int rc = NetIfList(list);
590 if (rc)
591 {
592 Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
593 }
594# else
595
596# if defined(RT_OS_DARWIN)
597 PDARWINETHERNIC pEtherNICs = DarwinGetEthernetControllers();
598 while (pEtherNICs)
599 {
600 ComObjPtr<HostNetworkInterface> IfObj;
601 IfObj.createObject();
602 if (SUCCEEDED(IfObj->init(Bstr(pEtherNICs->szName), Guid(pEtherNICs->Uuid), HostNetworkInterfaceType_Bridged)))
603 list.push_back(IfObj);
604
605 /* next, free current */
606 void *pvFree = pEtherNICs;
607 pEtherNICs = pEtherNICs->pNext;
608 RTMemFree(pvFree);
609 }
610
611# elif defined RT_OS_WINDOWS
612# ifndef VBOX_WITH_NETFLT
613 hr = E_NOTIMPL;
614# else /* # if defined VBOX_WITH_NETFLT */
615 INetCfg *pNc;
616 INetCfgComponent *pMpNcc;
617 INetCfgComponent *pTcpIpNcc;
618 LPWSTR lpszApp;
619 HRESULT hr;
620 IEnumNetCfgBindingPath *pEnumBp;
621 INetCfgBindingPath *pBp;
622 IEnumNetCfgBindingInterface *pEnumBi;
623 INetCfgBindingInterface *pBi;
624
625 /* we are using the INetCfg API for getting the list of miniports */
626 hr = VBoxNetCfgWinQueryINetCfg( FALSE,
627 VBOX_APP_NAME,
628 &pNc,
629 &lpszApp );
630 Assert(hr == S_OK);
631 if (hr == S_OK)
632 {
633# ifdef VBOX_NETFLT_ONDEMAND_BIND
634 /* for the protocol-based approach for now we just get all miniports the MS_TCPIP protocol binds to */
635 hr = pNc->FindComponent(L"MS_TCPIP", &pTcpIpNcc);
636# else
637 /* for the filter-based approach we get all miniports our filter (sun_VBoxNetFlt)is bound to */
638 hr = pNc->FindComponent(L"sun_VBoxNetFlt", &pTcpIpNcc);
639# ifndef VBOX_WITH_HARDENING
640 if (hr != S_OK)
641 {
642 /* TODO: try to install the netflt from here */
643 }
644# endif
645
646# endif
647
648 if (hr == S_OK)
649 {
650 hr = VBoxNetCfgWinGetBindingPathEnum(pTcpIpNcc, EBP_BELOW, &pEnumBp);
651 Assert(hr == S_OK);
652 if ( hr == S_OK )
653 {
654 hr = VBoxNetCfgWinGetFirstBindingPath(pEnumBp, &pBp);
655 Assert(hr == S_OK || hr == S_FALSE);
656 while( hr == S_OK )
657 {
658 /* S_OK == enabled, S_FALSE == disabled */
659 if (pBp->IsEnabled() == S_OK)
660 {
661 hr = VBoxNetCfgWinGetBindingInterfaceEnum(pBp, &pEnumBi);
662 Assert(hr == S_OK);
663 if ( hr == S_OK )
664 {
665 hr = VBoxNetCfgWinGetFirstBindingInterface(pEnumBi, &pBi);
666 Assert(hr == S_OK);
667 while(hr == S_OK)
668 {
669 hr = pBi->GetLowerComponent( &pMpNcc );
670 Assert(hr == S_OK);
671 if (hr == S_OK)
672 {
673 ULONG uComponentStatus;
674 hr = pMpNcc->GetDeviceStatus(&uComponentStatus);
675 Assert(hr == S_OK);
676 if (hr == S_OK)
677 {
678 if (uComponentStatus == 0)
679 {
680 vboxNetWinAddComponent(&list, pMpNcc);
681 }
682 }
683 VBoxNetCfgWinReleaseRef( pMpNcc );
684 }
685 VBoxNetCfgWinReleaseRef(pBi);
686
687 hr = VBoxNetCfgWinGetNextBindingInterface(pEnumBi, &pBi);
688 }
689 VBoxNetCfgWinReleaseRef(pEnumBi);
690 }
691 }
692 VBoxNetCfgWinReleaseRef(pBp);
693
694 hr = VBoxNetCfgWinGetNextBindingPath(pEnumBp, &pBp);
695 }
696 VBoxNetCfgWinReleaseRef(pEnumBp);
697 }
698 VBoxNetCfgWinReleaseRef(pTcpIpNcc);
699 }
700 else
701 {
702 LogRel(("failed to get the sun_VBoxNetFlt component, error (0x%x)\n", hr));
703 }
704
705 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE);
706 }
707# endif /* # if defined VBOX_WITH_NETFLT */
708
709
710# elif defined RT_OS_LINUX
711 int sock = socket(AF_INET, SOCK_DGRAM, 0);
712 if (sock >= 0)
713 {
714 char pBuffer[2048];
715 struct ifconf ifConf;
716 ifConf.ifc_len = sizeof(pBuffer);
717 ifConf.ifc_buf = pBuffer;
718 if (ioctl(sock, SIOCGIFCONF, &ifConf) >= 0)
719 {
720 for (struct ifreq *pReq = ifConf.ifc_req; (char*)pReq < pBuffer + ifConf.ifc_len; pReq++)
721 {
722 if (ioctl(sock, SIOCGIFHWADDR, pReq) >= 0)
723 {
724 if (pReq->ifr_hwaddr.sa_family == ARPHRD_ETHER)
725 {
726 RTUUID uuid;
727 Assert(sizeof(uuid) <= sizeof(*pReq));
728 memcpy(&uuid, pReq, sizeof(uuid));
729
730 ComObjPtr<HostNetworkInterface> IfObj;
731 IfObj.createObject();
732 if (SUCCEEDED(IfObj->init(Bstr(pReq->ifr_name), Guid(uuid), HostNetworkInterfaceType_Bridged)))
733 list.push_back(IfObj);
734 }
735 }
736 }
737 }
738 close(sock);
739 }
740# endif /* RT_OS_LINUX */
741# endif
742
743 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
744 for (it = list.begin(); it != list.end(); ++it)
745 {
746 (*it)->setVirtualBox(m->pParent);
747 }
748
749 SafeIfaceArray<IHostNetworkInterface> networkInterfaces (list);
750 networkInterfaces.detachTo(ComSafeArrayOutArg(aNetworkInterfaces));
751
752 return S_OK;
753
754#else
755 /* Not implemented / supported on this platform. */
756 ReturnComNotImplemented();
757#endif
758}
759
760STDMETHODIMP Host::COMGETTER(USBDevices)(ComSafeArrayOut(IHostUSBDevice*, aUSBDevices))
761{
762#ifdef VBOX_WITH_USB
763 CheckComArgOutSafeArrayPointerValid(aUSBDevices);
764
765 AutoCaller autoCaller(this);
766 if (FAILED(autoCaller.rc())) return autoCaller.rc();
767
768 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
769
770 HRESULT rc = checkUSBProxyService();
771 if (FAILED(rc)) return rc;
772
773 return m->pUSBProxyService->getDeviceCollection(ComSafeArrayOutArg(aUSBDevices));
774
775#else
776 /* Note: The GUI depends on this method returning E_NOTIMPL with no
777 * extended error info to indicate that USB is simply not available
778 * (w/o treating it as a failure), for example, as in OSE. */
779 NOREF(aUSBDevices);
780# ifndef RT_OS_WINDOWS
781 NOREF(aUSBDevicesSize);
782# endif
783 ReturnComNotImplemented();
784#endif
785}
786
787STDMETHODIMP Host::COMGETTER(USBDeviceFilters)(ComSafeArrayOut(IHostUSBDeviceFilter*, aUSBDeviceFilters))
788{
789#ifdef VBOX_WITH_USB
790 CheckComArgOutSafeArrayPointerValid(aUSBDeviceFilters);
791
792 AutoCaller autoCaller(this);
793 if (FAILED(autoCaller.rc())) return autoCaller.rc();
794
795 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
796
797 HRESULT rc = checkUSBProxyService();
798 if (FAILED(rc)) return rc;
799
800 SafeIfaceArray<IHostUSBDeviceFilter> collection(m->llUSBDeviceFilters);
801 collection.detachTo(ComSafeArrayOutArg(aUSBDeviceFilters));
802
803 return rc;
804#else
805 /* Note: The GUI depends on this method returning E_NOTIMPL with no
806 * extended error info to indicate that USB is simply not available
807 * (w/o treating it as a failure), for example, as in OSE. */
808 NOREF(aUSBDeviceFilters);
809# ifndef RT_OS_WINDOWS
810 NOREF(aUSBDeviceFiltersSize);
811# endif
812 ReturnComNotImplemented();
813#endif
814}
815
816/**
817 * Returns the number of installed logical processors
818 *
819 * @returns COM status code
820 * @param count address of result variable
821 */
822STDMETHODIMP Host::COMGETTER(ProcessorCount)(ULONG *aCount)
823{
824 CheckComArgOutPointerValid(aCount);
825 // no locking required
826
827 *aCount = RTMpGetPresentCount();
828 return S_OK;
829}
830
831/**
832 * Returns the number of online logical processors
833 *
834 * @returns COM status code
835 * @param count address of result variable
836 */
837STDMETHODIMP Host::COMGETTER(ProcessorOnlineCount)(ULONG *aCount)
838{
839 CheckComArgOutPointerValid(aCount);
840 // no locking required
841
842 *aCount = RTMpGetOnlineCount();
843 return S_OK;
844}
845
846/**
847 * Returns the number of installed physical processor cores.
848 *
849 * @returns COM status code
850 * @param count address of result variable
851 */
852STDMETHODIMP Host::COMGETTER(ProcessorCoreCount)(ULONG *aCount)
853{
854 CheckComArgOutPointerValid(aCount);
855 // no locking required
856
857 return E_NOTIMPL;
858}
859
860/**
861 * Returns the (approximate) maximum speed of the given host CPU in MHz
862 *
863 * @returns COM status code
864 * @param cpu id to get info for.
865 * @param speed address of result variable, speed is 0 if unknown or aCpuId is invalid.
866 */
867STDMETHODIMP Host::GetProcessorSpeed(ULONG aCpuId, ULONG *aSpeed)
868{
869 CheckComArgOutPointerValid(aSpeed);
870 // no locking required
871
872 *aSpeed = RTMpGetMaxFrequency(aCpuId);
873 return S_OK;
874}
875
876/**
877 * Returns a description string for the host CPU
878 *
879 * @returns COM status code
880 * @param cpu id to get info for.
881 * @param description address of result variable, empty string if not known or aCpuId is invalid.
882 */
883STDMETHODIMP Host::GetProcessorDescription(ULONG aCpuId, BSTR *aDescription)
884{
885 CheckComArgOutPointerValid(aDescription);
886 // no locking required
887
888 char szCPUModel[80];
889 int vrc = RTMpGetDescription(aCpuId, szCPUModel, sizeof(szCPUModel));
890 if (RT_FAILURE(vrc))
891 return E_FAIL; /** @todo error reporting? */
892 Bstr (szCPUModel).cloneTo(aDescription);
893 return S_OK;
894}
895
896/**
897 * Returns whether a host processor feature is supported or not
898 *
899 * @returns COM status code
900 * @param Feature to query.
901 * @param address of supported bool result variable
902 */
903STDMETHODIMP Host::GetProcessorFeature(ProcessorFeature_T aFeature, BOOL *aSupported)
904{
905 CheckComArgOutPointerValid(aSupported);
906 AutoCaller autoCaller(this);
907 if (FAILED(autoCaller.rc())) return autoCaller.rc();
908
909 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
910
911 switch (aFeature)
912 {
913 case ProcessorFeature_HWVirtEx:
914 *aSupported = m->fVTSupported;
915 break;
916
917 case ProcessorFeature_PAE:
918 *aSupported = m->fPAESupported;
919 break;
920
921 case ProcessorFeature_LongMode:
922 *aSupported = m->fLongModeSupported;
923 break;
924
925 case ProcessorFeature_NestedPaging:
926 *aSupported = m->fNestedPagingSupported;
927 break;
928
929 default:
930 ReturnComNotImplemented();
931 }
932 return S_OK;
933}
934
935/**
936 * Returns the specific CPUID leaf.
937 *
938 * @returns COM status code
939 * @param aCpuId The CPU number. Mostly ignored.
940 * @param aLeaf The leaf number.
941 * @param aSubLeaf The sub-leaf number.
942 * @param aValEAX Where to return EAX.
943 * @param aValEBX Where to return EBX.
944 * @param aValECX Where to return ECX.
945 * @param aValEDX Where to return EDX.
946 */
947STDMETHODIMP Host::GetProcessorCPUIDLeaf(ULONG aCpuId, ULONG aLeaf, ULONG aSubLeaf,
948 ULONG *aValEAX, ULONG *aValEBX, ULONG *aValECX, ULONG *aValEDX)
949{
950 CheckComArgOutPointerValid(aValEAX);
951 CheckComArgOutPointerValid(aValEBX);
952 CheckComArgOutPointerValid(aValECX);
953 CheckComArgOutPointerValid(aValEDX);
954 // no locking required
955
956 /* Check that the CPU is online. */
957 /** @todo later use RTMpOnSpecific. */
958 if (!RTMpIsCpuOnline(aCpuId))
959 return RTMpIsCpuPresent(aCpuId)
960 ? setError(E_FAIL, tr("CPU no.%u is not present"), aCpuId)
961 : setError(E_FAIL, tr("CPU no.%u is not online"), aCpuId);
962
963 uint32_t uEAX, uEBX, uECX, uEDX;
964 ASMCpuId_Idx_ECX(aLeaf, aSubLeaf, &uEAX, &uEBX, &uECX, &uEDX);
965 *aValEAX = uEAX;
966 *aValEBX = uEBX;
967 *aValECX = uECX;
968 *aValEDX = uEDX;
969
970 return S_OK;
971}
972
973/**
974 * Returns the amount of installed system memory in megabytes
975 *
976 * @returns COM status code
977 * @param size address of result variable
978 */
979STDMETHODIMP Host::COMGETTER(MemorySize)(ULONG *aSize)
980{
981 CheckComArgOutPointerValid(aSize);
982 // no locking required
983
984 /* @todo This is an ugly hack. There must be a function in IPRT for that. */
985 pm::CollectorHAL *hal = pm::createHAL();
986 if (!hal)
987 return E_FAIL;
988 ULONG tmp;
989 int rc = hal->getHostMemoryUsage(aSize, &tmp, &tmp);
990 *aSize /= 1024;
991 delete hal;
992 return rc;
993}
994
995/**
996 * Returns the current system memory free space in megabytes
997 *
998 * @returns COM status code
999 * @param available address of result variable
1000 */
1001STDMETHODIMP Host::COMGETTER(MemoryAvailable)(ULONG *aAvailable)
1002{
1003 CheckComArgOutPointerValid(aAvailable);
1004 // no locking required
1005
1006 /* @todo This is an ugly hack. There must be a function in IPRT for that. */
1007 pm::CollectorHAL *hal = pm::createHAL();
1008 if (!hal)
1009 return E_FAIL;
1010 ULONG tmp;
1011 int rc = hal->getHostMemoryUsage(&tmp, &tmp, aAvailable);
1012 *aAvailable /= 1024;
1013 delete hal;
1014 return rc;
1015}
1016
1017/**
1018 * Returns the name string of the host operating system
1019 *
1020 * @returns COM status code
1021 * @param os address of result variable
1022 */
1023STDMETHODIMP Host::COMGETTER(OperatingSystem)(BSTR *aOs)
1024{
1025 CheckComArgOutPointerValid(aOs);
1026 // no locking required
1027
1028 char szOSName[80];
1029 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szOSName, sizeof(szOSName));
1030 if (RT_FAILURE(vrc))
1031 return E_FAIL; /** @todo error reporting? */
1032 Bstr (szOSName).cloneTo(aOs);
1033 return S_OK;
1034}
1035
1036/**
1037 * Returns the version string of the host operating system
1038 *
1039 * @returns COM status code
1040 * @param os address of result variable
1041 */
1042STDMETHODIMP Host::COMGETTER(OSVersion)(BSTR *aVersion)
1043{
1044 CheckComArgOutPointerValid(aVersion);
1045 // no locking required
1046
1047 /* Get the OS release. Reserve some buffer space for the service pack. */
1048 char szOSRelease[128];
1049 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOSRelease, sizeof(szOSRelease) - 32);
1050 if (RT_FAILURE(vrc))
1051 return E_FAIL; /** @todo error reporting? */
1052
1053 /* Append the service pack if present. */
1054 char szOSServicePack[80];
1055 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szOSServicePack, sizeof(szOSServicePack));
1056 if (RT_FAILURE(vrc))
1057 {
1058 if (vrc != VERR_NOT_SUPPORTED)
1059 return E_FAIL; /** @todo error reporting? */
1060 szOSServicePack[0] = '\0';
1061 }
1062 if (szOSServicePack[0] != '\0')
1063 {
1064 char *psz = strchr(szOSRelease, '\0');
1065 RTStrPrintf(psz, &szOSRelease[sizeof(szOSRelease)] - psz, "sp%s", szOSServicePack);
1066 }
1067
1068 Bstr(szOSRelease).cloneTo(aVersion);
1069 return S_OK;
1070}
1071
1072/**
1073 * Returns the current host time in milliseconds since 1970-01-01 UTC.
1074 *
1075 * @returns COM status code
1076 * @param time address of result variable
1077 */
1078STDMETHODIMP Host::COMGETTER(UTCTime)(LONG64 *aUTCTime)
1079{
1080 CheckComArgOutPointerValid(aUTCTime);
1081 // no locking required
1082
1083 RTTIMESPEC now;
1084 *aUTCTime = RTTimeSpecGetMilli(RTTimeNow(&now));
1085
1086 return S_OK;
1087}
1088
1089STDMETHODIMP Host::COMGETTER(Acceleration3DAvailable)(BOOL *aSupported)
1090{
1091 CheckComArgOutPointerValid(aSupported);
1092 AutoCaller autoCaller(this);
1093 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1094
1095 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1096
1097 *aSupported = m->f3DAccelerationSupported;
1098
1099#ifdef DEBUG_misha
1100 AssertMsgFailed(("should not be here any more!\n"));
1101#endif
1102
1103 return S_OK;
1104}
1105
1106STDMETHODIMP Host::CreateHostOnlyNetworkInterface(IHostNetworkInterface **aHostNetworkInterface,
1107 IProgress **aProgress)
1108{
1109 CheckComArgOutPointerValid(aHostNetworkInterface);
1110 CheckComArgOutPointerValid(aProgress);
1111
1112 AutoCaller autoCaller(this);
1113 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1114
1115#ifdef VBOX_WITH_HOSTNETIF_API
1116 /* No need to lock anything. If there ever will - watch out, the function
1117 * called below grabs the VirtualBox lock. */
1118
1119 int r = NetIfCreateHostOnlyNetworkInterface(m->pParent, aHostNetworkInterface, aProgress);
1120 if (RT_SUCCESS(r))
1121 {
1122 if (!*aHostNetworkInterface)
1123 return setError(E_FAIL,
1124 tr("Unable to create a host network interface"));
1125
1126#if !defined(RT_OS_WINDOWS)
1127 Bstr tmpAddr, tmpMask, tmpName;
1128 HRESULT hrc;
1129 hrc = (*aHostNetworkInterface)->COMGETTER(Name)(tmpName.asOutParam());
1130 ComAssertComRCRet(hrc, hrc);
1131 hrc = (*aHostNetworkInterface)->COMGETTER(IPAddress)(tmpAddr.asOutParam());
1132 ComAssertComRCRet(hrc, hrc);
1133 hrc = (*aHostNetworkInterface)->COMGETTER(NetworkMask)(tmpMask.asOutParam());
1134 ComAssertComRCRet(hrc, hrc);
1135 /*
1136 * We need to write the default IP address and mask to extra data now,
1137 * so the interface gets re-created after vboxnetadp.ko reload.
1138 * Note that we avoid calling EnableStaticIpConfig since it would
1139 * change the address on host's interface as well and we want to
1140 * postpone the change until VM actually starts.
1141 */
1142 hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPAddress",
1143 tmpName.raw()).raw(),
1144 tmpAddr.raw());
1145 ComAssertComRCRet(hrc, hrc);
1146
1147 hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPNetMask",
1148 tmpName.raw()).raw(),
1149 tmpMask.raw());
1150 ComAssertComRCRet(hrc, hrc);
1151#endif
1152 }
1153
1154 return S_OK;
1155#else
1156 return E_NOTIMPL;
1157#endif
1158}
1159
1160STDMETHODIMP Host::RemoveHostOnlyNetworkInterface(IN_BSTR aId,
1161 IProgress **aProgress)
1162{
1163 CheckComArgOutPointerValid(aProgress);
1164
1165 AutoCaller autoCaller(this);
1166 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1167
1168#ifdef VBOX_WITH_HOSTNETIF_API
1169 /* No need to lock anything, the code below does not touch the state
1170 * of the host object. If that ever changes then check for lock order
1171 * violations with the called functions. */
1172
1173 Bstr name;
1174 HRESULT rc;
1175
1176 /* first check whether an interface with the given name already exists */
1177 {
1178 ComPtr<IHostNetworkInterface> iface;
1179 if (FAILED(FindHostNetworkInterfaceById(aId,
1180 iface.asOutParam())))
1181 return setError(VBOX_E_OBJECT_NOT_FOUND,
1182 tr("Host network interface with UUID {%RTuuid} does not exist"),
1183 Guid (aId).raw());
1184 rc = iface->COMGETTER(Name)(name.asOutParam());
1185 ComAssertComRCRet(rc, rc);
1186 }
1187
1188 int r = NetIfRemoveHostOnlyNetworkInterface(m->pParent, Guid(aId).ref(), aProgress);
1189 if (RT_SUCCESS(r))
1190 {
1191 /* Drop configuration parameters for removed interface */
1192 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPAddress", name.raw()).raw(), NULL);
1193 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPNetMask", name.raw()).raw(), NULL);
1194 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPV6Address", name.raw()).raw(), NULL);
1195 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPV6NetMask", name.raw()).raw(), NULL);
1196
1197 return S_OK;
1198 }
1199
1200 return r == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
1201#else
1202 return E_NOTIMPL;
1203#endif
1204}
1205
1206STDMETHODIMP Host::CreateUSBDeviceFilter(IN_BSTR aName,
1207 IHostUSBDeviceFilter **aFilter)
1208{
1209#ifdef VBOX_WITH_USB
1210 CheckComArgStrNotEmptyOrNull(aName);
1211 CheckComArgOutPointerValid(aFilter);
1212
1213 AutoCaller autoCaller(this);
1214 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1215
1216 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1217
1218 ComObjPtr<HostUSBDeviceFilter> filter;
1219 filter.createObject();
1220 HRESULT rc = filter->init(this, aName);
1221 ComAssertComRCRet(rc, rc);
1222 rc = filter.queryInterfaceTo(aFilter);
1223 AssertComRCReturn(rc, rc);
1224 return S_OK;
1225#else
1226 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1227 * extended error info to indicate that USB is simply not available
1228 * (w/o treating it as a failure), for example, as in OSE. */
1229 NOREF(aName);
1230 NOREF(aFilter);
1231 ReturnComNotImplemented();
1232#endif
1233}
1234
1235STDMETHODIMP Host::InsertUSBDeviceFilter(ULONG aPosition,
1236 IHostUSBDeviceFilter *aFilter)
1237{
1238#ifdef VBOX_WITH_USB
1239 CheckComArgNotNull(aFilter);
1240
1241 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1242 AutoCaller autoCaller(this);
1243 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1244
1245 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1246
1247 clearError();
1248 MultiResult rc = checkUSBProxyService();
1249 if (FAILED(rc)) return rc;
1250
1251 ComObjPtr<HostUSBDeviceFilter> pFilter;
1252 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
1253 it != m->llChildren.end();
1254 ++it)
1255 {
1256 if (*it == aFilter)
1257 {
1258 pFilter = *it;
1259 break;
1260 }
1261 }
1262 if (pFilter.isNull())
1263 return setError(VBOX_E_INVALID_OBJECT_STATE,
1264 tr("The given USB device filter is not created within this VirtualBox instance"));
1265
1266 if (pFilter->mInList)
1267 return setError(E_INVALIDARG,
1268 tr("The given USB device filter is already in the list"));
1269
1270 /* iterate to the position... */
1271 USBDeviceFilterList::iterator itPos = m->llUSBDeviceFilters.begin();
1272 std::advance(itPos, aPosition);
1273 /* ...and insert */
1274 m->llUSBDeviceFilters.insert(itPos, pFilter);
1275 pFilter->mInList = true;
1276
1277 /* notify the proxy (only when the filter is active) */
1278 if ( m->pUSBProxyService->isActive()
1279 && pFilter->getData().mActive)
1280 {
1281 ComAssertRet(pFilter->getId() == NULL, E_FAIL);
1282 pFilter->getId() = m->pUSBProxyService->insertFilter(&pFilter->getData().mUSBFilter);
1283 }
1284
1285 // save the global settings; for that we should hold only the VirtualBox lock
1286 alock.release();
1287 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
1288 return rc = m->pParent->saveSettings();
1289#else
1290 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1291 * extended error info to indicate that USB is simply not available
1292 * (w/o treating it as a failure), for example, as in OSE. */
1293 NOREF(aPosition);
1294 NOREF(aFilter);
1295 ReturnComNotImplemented();
1296#endif
1297}
1298
1299STDMETHODIMP Host::RemoveUSBDeviceFilter(ULONG aPosition)
1300{
1301#ifdef VBOX_WITH_USB
1302
1303 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1304 AutoCaller autoCaller(this);
1305 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1306
1307 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1308
1309 clearError();
1310 MultiResult rc = checkUSBProxyService();
1311 if (FAILED(rc)) return rc;
1312
1313 if (!m->llUSBDeviceFilters.size())
1314 return setError(E_INVALIDARG,
1315 tr("The USB device filter list is empty"));
1316
1317 if (aPosition >= m->llUSBDeviceFilters.size())
1318 return setError(E_INVALIDARG,
1319 tr("Invalid position: %lu (must be in range [0, %lu])"),
1320 aPosition, m->llUSBDeviceFilters.size() - 1);
1321
1322 ComObjPtr<HostUSBDeviceFilter> filter;
1323 {
1324 /* iterate to the position... */
1325 USBDeviceFilterList::iterator it = m->llUSBDeviceFilters.begin();
1326 std::advance (it, aPosition);
1327 /* ...get an element from there... */
1328 filter = *it;
1329 /* ...and remove */
1330 filter->mInList = false;
1331 m->llUSBDeviceFilters.erase(it);
1332 }
1333
1334 /* notify the proxy (only when the filter is active) */
1335 if (m->pUSBProxyService->isActive() && filter->getData().mActive)
1336 {
1337 ComAssertRet(filter->getId() != NULL, E_FAIL);
1338 m->pUSBProxyService->removeFilter(filter->getId());
1339 filter->getId() = NULL;
1340 }
1341
1342 // save the global settings; for that we should hold only the VirtualBox lock
1343 alock.release();
1344 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
1345 return rc = m->pParent->saveSettings();
1346#else
1347 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1348 * extended error info to indicate that USB is simply not available
1349 * (w/o treating it as a failure), for example, as in OSE. */
1350 NOREF(aPosition);
1351 ReturnComNotImplemented();
1352#endif
1353}
1354
1355STDMETHODIMP Host::FindHostDVDDrive(IN_BSTR aName, IMedium **aDrive)
1356{
1357 CheckComArgStrNotEmptyOrNull(aName);
1358 CheckComArgOutPointerValid(aDrive);
1359
1360 ComObjPtr<Medium>medium;
1361 HRESULT rc = findHostDriveByNameOrId(DeviceType_DVD, Utf8Str(aName), medium);
1362 if (SUCCEEDED(rc))
1363 return medium.queryInterfaceTo(aDrive);
1364 else
1365 return setError(rc, Medium::tr("The host DVD drive named '%ls' could not be found"), aName);
1366}
1367
1368STDMETHODIMP Host::FindHostFloppyDrive(IN_BSTR aName, IMedium **aDrive)
1369{
1370 CheckComArgStrNotEmptyOrNull(aName);
1371 CheckComArgOutPointerValid(aDrive);
1372
1373 *aDrive = NULL;
1374
1375 ComObjPtr<Medium>medium;
1376 HRESULT rc = findHostDriveByNameOrId(DeviceType_Floppy, Utf8Str(aName), medium);
1377 if (SUCCEEDED(rc))
1378 return medium.queryInterfaceTo(aDrive);
1379 else
1380 return setError(rc, Medium::tr("The host floppy drive named '%ls' could not be found"), aName);
1381}
1382
1383STDMETHODIMP Host::FindHostNetworkInterfaceByName(IN_BSTR name, IHostNetworkInterface **networkInterface)
1384{
1385#ifndef VBOX_WITH_HOSTNETIF_API
1386 return E_NOTIMPL;
1387#else
1388 if (!name)
1389 return E_INVALIDARG;
1390 if (!networkInterface)
1391 return E_POINTER;
1392
1393 *networkInterface = NULL;
1394 ComObjPtr<HostNetworkInterface> found;
1395 std::list <ComObjPtr<HostNetworkInterface> > list;
1396 int rc = NetIfList(list);
1397 if (RT_FAILURE(rc))
1398 {
1399 Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
1400 return E_FAIL;
1401 }
1402 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
1403 for (it = list.begin(); it != list.end(); ++it)
1404 {
1405 Bstr n;
1406 (*it)->COMGETTER(Name) (n.asOutParam());
1407 if (n == name)
1408 found = *it;
1409 }
1410
1411 if (!found)
1412 return setError(E_INVALIDARG,
1413 HostNetworkInterface::tr("The host network interface with the given name could not be found"));
1414
1415 found->setVirtualBox(m->pParent);
1416
1417 return found.queryInterfaceTo(networkInterface);
1418#endif
1419}
1420
1421STDMETHODIMP Host::FindHostNetworkInterfaceById(IN_BSTR id, IHostNetworkInterface **networkInterface)
1422{
1423#ifndef VBOX_WITH_HOSTNETIF_API
1424 return E_NOTIMPL;
1425#else
1426 if (Guid(id).isEmpty())
1427 return E_INVALIDARG;
1428 if (!networkInterface)
1429 return E_POINTER;
1430
1431 *networkInterface = NULL;
1432 ComObjPtr<HostNetworkInterface> found;
1433 std::list <ComObjPtr<HostNetworkInterface> > list;
1434 int rc = NetIfList(list);
1435 if (RT_FAILURE(rc))
1436 {
1437 Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
1438 return E_FAIL;
1439 }
1440 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
1441 for (it = list.begin(); it != list.end(); ++it)
1442 {
1443 Bstr g;
1444 (*it)->COMGETTER(Id) (g.asOutParam());
1445 if (g == id)
1446 found = *it;
1447 }
1448
1449 if (!found)
1450 return setError(E_INVALIDARG,
1451 HostNetworkInterface::tr("The host network interface with the given GUID could not be found"));
1452
1453 found->setVirtualBox(m->pParent);
1454
1455 return found.queryInterfaceTo(networkInterface);
1456#endif
1457}
1458
1459STDMETHODIMP Host::FindHostNetworkInterfacesOfType(HostNetworkInterfaceType_T type,
1460 ComSafeArrayOut(IHostNetworkInterface *, aNetworkInterfaces))
1461{
1462#ifdef VBOX_WITH_HOSTNETIF_API
1463 std::list <ComObjPtr<HostNetworkInterface> > allList;
1464 int rc = NetIfList(allList);
1465 if (RT_FAILURE(rc))
1466 return E_FAIL;
1467
1468 std::list <ComObjPtr<HostNetworkInterface> > resultList;
1469
1470 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
1471 for (it = allList.begin(); it != allList.end(); ++it)
1472 {
1473 HostNetworkInterfaceType_T t;
1474 HRESULT hr = (*it)->COMGETTER(InterfaceType)(&t);
1475 if (FAILED(hr))
1476 return hr;
1477
1478 if (t == type)
1479 {
1480 (*it)->setVirtualBox(m->pParent);
1481 resultList.push_back (*it);
1482 }
1483 }
1484
1485 SafeIfaceArray<IHostNetworkInterface> filteredNetworkInterfaces (resultList);
1486 filteredNetworkInterfaces.detachTo(ComSafeArrayOutArg(aNetworkInterfaces));
1487
1488 return S_OK;
1489#else
1490 return E_NOTIMPL;
1491#endif
1492}
1493
1494STDMETHODIMP Host::FindUSBDeviceByAddress(IN_BSTR aAddress,
1495 IHostUSBDevice **aDevice)
1496{
1497#ifdef VBOX_WITH_USB
1498 CheckComArgStrNotEmptyOrNull(aAddress);
1499 CheckComArgOutPointerValid(aDevice);
1500
1501 *aDevice = NULL;
1502
1503 SafeIfaceArray<IHostUSBDevice> devsvec;
1504 HRESULT rc = COMGETTER(USBDevices) (ComSafeArrayAsOutParam(devsvec));
1505 if (FAILED(rc)) return rc;
1506
1507 for (size_t i = 0; i < devsvec.size(); ++i)
1508 {
1509 Bstr address;
1510 rc = devsvec[i]->COMGETTER(Address) (address.asOutParam());
1511 if (FAILED(rc)) return rc;
1512 if (address == aAddress)
1513 {
1514 return ComObjPtr<IHostUSBDevice> (devsvec[i]).queryInterfaceTo(aDevice);
1515 }
1516 }
1517
1518 return setErrorNoLog(VBOX_E_OBJECT_NOT_FOUND,
1519 tr("Could not find a USB device with address '%ls'"),
1520 aAddress);
1521
1522#else /* !VBOX_WITH_USB */
1523 NOREF(aAddress);
1524 NOREF(aDevice);
1525 return E_NOTIMPL;
1526#endif /* !VBOX_WITH_USB */
1527}
1528
1529STDMETHODIMP Host::FindUSBDeviceById(IN_BSTR aId,
1530 IHostUSBDevice **aDevice)
1531{
1532#ifdef VBOX_WITH_USB
1533 CheckComArgExpr(aId, Guid (aId).isEmpty() == false);
1534 CheckComArgOutPointerValid(aDevice);
1535
1536 *aDevice = NULL;
1537
1538 SafeIfaceArray<IHostUSBDevice> devsvec;
1539 HRESULT rc = COMGETTER(USBDevices) (ComSafeArrayAsOutParam(devsvec));
1540 if (FAILED(rc)) return rc;
1541
1542 for (size_t i = 0; i < devsvec.size(); ++i)
1543 {
1544 Bstr id;
1545 rc = devsvec[i]->COMGETTER(Id) (id.asOutParam());
1546 if (FAILED(rc)) return rc;
1547 if (id == aId)
1548 {
1549 return ComObjPtr<IHostUSBDevice> (devsvec[i]).queryInterfaceTo(aDevice);
1550 }
1551 }
1552
1553 return setErrorNoLog (VBOX_E_OBJECT_NOT_FOUND, tr (
1554 "Could not find a USB device with uuid {%RTuuid}"),
1555 Guid (aId).raw());
1556
1557#else /* !VBOX_WITH_USB */
1558 NOREF(aId);
1559 NOREF(aDevice);
1560 return E_NOTIMPL;
1561#endif /* !VBOX_WITH_USB */
1562}
1563
1564STDMETHODIMP Host::GenerateMACAddress(BSTR *aAddress)
1565{
1566 CheckComArgOutPointerValid(aAddress);
1567 // no locking required
1568 Utf8Str mac;
1569 generateMACAddress(mac);
1570 Bstr(mac).cloneTo(aAddress);
1571 return S_OK;
1572}
1573
1574// public methods only for internal purposes
1575////////////////////////////////////////////////////////////////////////////////
1576
1577HRESULT Host::loadSettings(const settings::Host &data)
1578{
1579 HRESULT rc = S_OK;
1580#ifdef VBOX_WITH_USB
1581 AutoCaller autoCaller(this);
1582 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1583
1584 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1585
1586 for (settings::USBDeviceFiltersList::const_iterator it = data.llUSBDeviceFilters.begin();
1587 it != data.llUSBDeviceFilters.end();
1588 ++it)
1589 {
1590 const settings::USBDeviceFilter &f = *it;
1591 ComObjPtr<HostUSBDeviceFilter> pFilter;
1592 pFilter.createObject();
1593 rc = pFilter->init(this, f);
1594 if (FAILED(rc)) break;
1595
1596 m->llUSBDeviceFilters.push_back(pFilter);
1597 pFilter->mInList = true;
1598
1599 /* notify the proxy (only when the filter is active) */
1600 if (pFilter->getData().mActive)
1601 {
1602 HostUSBDeviceFilter *flt = pFilter; /* resolve ambiguity */
1603 flt->getId() = m->pUSBProxyService->insertFilter(&pFilter->getData().mUSBFilter);
1604 }
1605 }
1606#else
1607 NOREF(data);
1608#endif /* VBOX_WITH_USB */
1609 return rc;
1610}
1611
1612HRESULT Host::saveSettings(settings::Host &data)
1613{
1614#ifdef VBOX_WITH_USB
1615 AutoCaller autoCaller(this);
1616 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1617
1618 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1619
1620 data.llUSBDeviceFilters.clear();
1621
1622 for (USBDeviceFilterList::const_iterator it = m->llUSBDeviceFilters.begin();
1623 it != m->llUSBDeviceFilters.end();
1624 ++it)
1625 {
1626 ComObjPtr<HostUSBDeviceFilter> pFilter = *it;
1627 settings::USBDeviceFilter f;
1628 pFilter->saveSettings(f);
1629 data.llUSBDeviceFilters.push_back(f);
1630 }
1631#else
1632 NOREF(data);
1633#endif /* VBOX_WITH_USB */
1634
1635 return S_OK;
1636}
1637
1638/**
1639 * Sets the given pointer to point to the static list of DVD or floppy
1640 * drives in the Host instance data, depending on the @a mediumType
1641 * parameter.
1642 *
1643 * This builds the list on the first call; it adds or removes host drives
1644 * that may have changed if fRefresh == true.
1645 *
1646 * The caller must hold the medium tree write lock before calling this.
1647 * To protect the list to which the caller's pointer points, the caller
1648 * must also hold that lock.
1649 *
1650 * @param mediumType Must be DeviceType_Floppy or DeviceType_DVD.
1651 * @param fRefresh Whether to refresh the host drives list even if this is not the first call.
1652 * @param pll Caller's pointer which gets set to the static list of host drives.
1653 * @return
1654 */
1655HRESULT Host::getDrives(DeviceType_T mediumType,
1656 bool fRefresh,
1657 MediaList *&pll)
1658{
1659 HRESULT rc = S_OK;
1660 Assert(m->pParent->getMediaTreeLockHandle().isWriteLockOnCurrentThread());
1661
1662 MediaList llNew;
1663 MediaList *pllCached;
1664 bool *pfListBuilt = NULL;
1665
1666 switch (mediumType)
1667 {
1668 case DeviceType_DVD:
1669 if (!m->fDVDDrivesListBuilt || fRefresh)
1670 {
1671 rc = buildDVDDrivesList(llNew);
1672 if (FAILED(rc))
1673 return rc;
1674 pfListBuilt = &m->fDVDDrivesListBuilt;
1675 }
1676 pllCached = &m->llDVDDrives;
1677 break;
1678
1679 case DeviceType_Floppy:
1680 if (!m->fFloppyDrivesListBuilt || fRefresh)
1681 {
1682 rc = buildFloppyDrivesList(llNew);
1683 if (FAILED(rc))
1684 return rc;
1685 pfListBuilt = &m->fFloppyDrivesListBuilt;
1686 }
1687 pllCached = &m->llFloppyDrives;
1688 break;
1689
1690 default:
1691 return E_INVALIDARG;
1692 }
1693
1694 if (pfListBuilt)
1695 {
1696 // a list was built in llNew above:
1697 if (!*pfListBuilt)
1698 {
1699 // this was the first call (instance bool is still false): then just copy the whole list and return
1700 *pllCached = llNew;
1701 // and mark the instance data as "built"
1702 *pfListBuilt = true;
1703 }
1704 else
1705 {
1706 // list was built, and this was a subsequent call: then compare the old and the new lists
1707
1708 // remove drives from the cached list which are no longer present
1709 for (MediaList::iterator itCached = pllCached->begin();
1710 itCached != pllCached->end();
1711 /*nothing */)
1712 {
1713 Medium *pCached = *itCached;
1714 const Utf8Str strLocationCached = pCached->getLocationFull();
1715 bool fFound = false;
1716 for (MediaList::iterator itNew = llNew.begin();
1717 itNew != llNew.end();
1718 ++itNew)
1719 {
1720 Medium *pNew = *itNew;
1721 const Utf8Str strLocationNew = pNew->getLocationFull();
1722 if (strLocationNew == strLocationCached)
1723 {
1724 fFound = true;
1725 break;
1726 }
1727 }
1728 if (!fFound)
1729 itCached = pllCached->erase(itCached);
1730 else
1731 ++itCached;
1732 }
1733
1734 // add drives to the cached list that are not on there yet
1735 for (MediaList::iterator itNew = llNew.begin();
1736 itNew != llNew.end();
1737 ++itNew)
1738 {
1739 Medium *pNew = *itNew;
1740 const Utf8Str strLocationNew = pNew->getLocationFull();
1741 bool fFound = false;
1742 for (MediaList::iterator itCached = pllCached->begin();
1743 itCached != pllCached->end();
1744 ++itCached)
1745 {
1746 Medium *pCached = *itCached;
1747 const Utf8Str strLocationCached = pCached->getLocationFull();
1748 if (strLocationNew == strLocationCached)
1749 {
1750 fFound = true;
1751 break;
1752 }
1753 }
1754
1755 if (!fFound)
1756 pllCached->push_back(pNew);
1757 }
1758 }
1759 }
1760
1761 // return cached list to caller
1762 pll = pllCached;
1763
1764 return rc;
1765}
1766
1767/**
1768 * Goes through the list of host drives that would be returned by getDrives()
1769 * and looks for a host drive with the given UUID. If found, it sets pMedium
1770 * to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
1771 *
1772 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
1773 * @param uuid Medium UUID of host drive to look for.
1774 * @param fRefresh Whether to refresh the host drives list (see getDrives())
1775 * @param pMedium Medium object, if found…
1776 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
1777 */
1778HRESULT Host::findHostDriveById(DeviceType_T mediumType,
1779 const Guid &uuid,
1780 bool fRefresh,
1781 ComObjPtr<Medium> &pMedium)
1782{
1783 MediaList *pllMedia;
1784
1785 AutoWriteLock wlock(m->pParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
1786 HRESULT rc = getDrives(mediumType, fRefresh, pllMedia);
1787 if (SUCCEEDED(rc))
1788 {
1789 for (MediaList::iterator it = pllMedia->begin();
1790 it != pllMedia->end();
1791 ++it)
1792 {
1793 Medium *pThis = *it;
1794 AutoCaller mediumCaller(pThis);
1795 AutoReadLock mediumLock(pThis COMMA_LOCKVAL_SRC_POS);
1796 if (pThis->getId() == uuid)
1797 {
1798 pMedium = pThis;
1799 return S_OK;
1800 }
1801 }
1802 }
1803
1804 return VBOX_E_OBJECT_NOT_FOUND;
1805}
1806
1807/**
1808 * Goes through the list of host drives that would be returned by getDrives()
1809 * and looks for a host drive with the given name. If found, it sets pMedium
1810 * to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
1811 *
1812 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
1813 * @param strLocationFull Name (path) of host drive to look for.
1814 * @param fRefresh Whether to refresh the host drives list (see getDrives())
1815 * @param pMedium Medium object, if found…
1816 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
1817 */
1818HRESULT Host::findHostDriveByName(DeviceType_T mediumType,
1819 const Utf8Str &strLocationFull,
1820 bool fRefresh,
1821 ComObjPtr<Medium> &pMedium)
1822{
1823 MediaList *pllMedia;
1824
1825 AutoWriteLock wlock(m->pParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
1826 HRESULT rc = getDrives(mediumType, fRefresh, pllMedia);
1827 if (SUCCEEDED(rc))
1828 {
1829 for (MediaList::iterator it = pllMedia->begin();
1830 it != pllMedia->end();
1831 ++it)
1832 {
1833 Medium *pThis = *it;
1834 AutoCaller mediumCaller(pThis);
1835 AutoReadLock mediumLock(pThis COMMA_LOCKVAL_SRC_POS);
1836 if (pThis->getLocationFull() == strLocationFull)
1837 {
1838 pMedium = pThis;
1839 return S_OK;
1840 }
1841 }
1842 }
1843
1844 return VBOX_E_OBJECT_NOT_FOUND;
1845}
1846
1847/**
1848 * Goes through the list of host drives that would be returned by getDrives()
1849 * and looks for a host drive with the given name, location or ID. If found,
1850 * it sets pMedium to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
1851 *
1852 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
1853 * @param strNameOrId Name or full location or UUID of host drive to look for.
1854 * @param pMedium Medium object, if found…
1855 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
1856 */
1857HRESULT Host::findHostDriveByNameOrId(DeviceType_T mediumType,
1858 const Utf8Str &strNameOrId,
1859 ComObjPtr<Medium> &pMedium)
1860{
1861 AutoWriteLock wlock(m->pParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
1862
1863 Guid uuid(strNameOrId);
1864 if (!uuid.isEmpty())
1865 return findHostDriveById(mediumType, uuid, true /* fRefresh */, pMedium);
1866
1867 // string is not a syntactically valid UUID: try a name then
1868 return findHostDriveByName(mediumType, strNameOrId, true /* fRefresh */, pMedium);
1869}
1870
1871/**
1872 * Called from getDrives() to build the DVD drives list.
1873 * @param pll
1874 * @return
1875 */
1876HRESULT Host::buildDVDDrivesList(MediaList &list)
1877{
1878 HRESULT rc = S_OK;
1879
1880 Assert(m->pParent->getMediaTreeLockHandle().isWriteLockOnCurrentThread());
1881
1882 try
1883 {
1884#if defined(RT_OS_WINDOWS)
1885 int sz = GetLogicalDriveStrings(0, NULL);
1886 TCHAR *hostDrives = new TCHAR[sz+1];
1887 GetLogicalDriveStrings(sz, hostDrives);
1888 wchar_t driveName[3] = { '?', ':', '\0' };
1889 TCHAR *p = hostDrives;
1890 do
1891 {
1892 if (GetDriveType(p) == DRIVE_CDROM)
1893 {
1894 driveName[0] = *p;
1895 ComObjPtr<Medium> hostDVDDriveObj;
1896 hostDVDDriveObj.createObject();
1897 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(driveName));
1898 list.push_back(hostDVDDriveObj);
1899 }
1900 p += _tcslen(p) + 1;
1901 }
1902 while (*p);
1903 delete[] hostDrives;
1904
1905#elif defined(RT_OS_SOLARIS)
1906# ifdef VBOX_USE_LIBHAL
1907 if (!getDVDInfoFromHal(list))
1908# endif
1909 {
1910 getDVDInfoFromDevTree(list);
1911 }
1912
1913#elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
1914 if (RT_SUCCESS(m->hostDrives.updateDVDs()))
1915 for (DriveInfoList::const_iterator it = m->hostDrives.DVDBegin();
1916 SUCCEEDED(rc) && it != m->hostDrives.DVDEnd(); ++it)
1917 {
1918 ComObjPtr<Medium> hostDVDDriveObj;
1919 Utf8Str location(it->mDevice);
1920 Utf8Str description(it->mDescription);
1921 if (SUCCEEDED(rc))
1922 rc = hostDVDDriveObj.createObject();
1923 if (SUCCEEDED(rc))
1924 rc = hostDVDDriveObj->init(m->pParent, DeviceType_DVD, location, description);
1925 if (SUCCEEDED(rc))
1926 list.push_back(hostDVDDriveObj);
1927 }
1928#elif defined(RT_OS_DARWIN)
1929 PDARWINDVD cur = DarwinGetDVDDrives();
1930 while (cur)
1931 {
1932 ComObjPtr<Medium> hostDVDDriveObj;
1933 hostDVDDriveObj.createObject();
1934 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(cur->szName));
1935 list.push_back(hostDVDDriveObj);
1936
1937 /* next */
1938 void *freeMe = cur;
1939 cur = cur->pNext;
1940 RTMemFree(freeMe);
1941 }
1942#else
1943 /* PORTME */
1944#endif
1945 }
1946 catch(std::bad_alloc &)
1947 {
1948 rc = E_OUTOFMEMORY;
1949 }
1950 return rc;
1951}
1952
1953/**
1954 * Called from getDrives() to build the floppy drives list.
1955 * @param list
1956 * @return
1957 */
1958HRESULT Host::buildFloppyDrivesList(MediaList &list)
1959{
1960 HRESULT rc = S_OK;
1961
1962 Assert(m->pParent->getMediaTreeLockHandle().isWriteLockOnCurrentThread());
1963
1964 try
1965 {
1966#ifdef RT_OS_WINDOWS
1967 int sz = GetLogicalDriveStrings(0, NULL);
1968 TCHAR *hostDrives = new TCHAR[sz+1];
1969 GetLogicalDriveStrings(sz, hostDrives);
1970 wchar_t driveName[3] = { '?', ':', '\0' };
1971 TCHAR *p = hostDrives;
1972 do
1973 {
1974 if (GetDriveType(p) == DRIVE_REMOVABLE)
1975 {
1976 driveName[0] = *p;
1977 ComObjPtr<Medium> hostFloppyDriveObj;
1978 hostFloppyDriveObj.createObject();
1979 hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, Bstr(driveName));
1980 list.push_back(hostFloppyDriveObj);
1981 }
1982 p += _tcslen(p) + 1;
1983 }
1984 while (*p);
1985 delete[] hostDrives;
1986#elif defined(RT_OS_LINUX)
1987 if (RT_SUCCESS(m->hostDrives.updateFloppies()))
1988 for (DriveInfoList::const_iterator it = m->hostDrives.FloppyBegin();
1989 SUCCEEDED(rc) && it != m->hostDrives.FloppyEnd(); ++it)
1990 {
1991 ComObjPtr<Medium> hostFloppyDriveObj;
1992 Utf8Str location(it->mDevice);
1993 Utf8Str description(it->mDescription);
1994 if (SUCCEEDED(rc))
1995 rc = hostFloppyDriveObj.createObject();
1996 if (SUCCEEDED(rc))
1997 rc = hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, location, description);
1998 if (SUCCEEDED(rc))
1999 list.push_back(hostFloppyDriveObj);
2000 }
2001#else
2002 NOREF(list);
2003 /* PORTME */
2004#endif
2005 }
2006 catch(std::bad_alloc &)
2007 {
2008 rc = E_OUTOFMEMORY;
2009 }
2010
2011 return rc;
2012}
2013
2014#ifdef VBOX_WITH_USB
2015USBProxyService* Host::usbProxyService()
2016{
2017 return m->pUSBProxyService;
2018}
2019
2020HRESULT Host::addChild(HostUSBDeviceFilter *pChild)
2021{
2022 AutoCaller autoCaller(this);
2023 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2024
2025 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2026
2027 m->llChildren.push_back(pChild);
2028
2029 return S_OK;
2030}
2031
2032HRESULT Host::removeChild(HostUSBDeviceFilter *pChild)
2033{
2034 AutoCaller autoCaller(this);
2035 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2036
2037 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2038
2039 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
2040 it != m->llChildren.end();
2041 ++it)
2042 {
2043 if (*it == pChild)
2044 {
2045 m->llChildren.erase(it);
2046 break;
2047 }
2048 }
2049
2050 return S_OK;
2051}
2052
2053VirtualBox* Host::parent()
2054{
2055 return m->pParent;
2056}
2057
2058/**
2059 * Called by setter methods of all USB device filters.
2060 */
2061HRESULT Host::onUSBDeviceFilterChange(HostUSBDeviceFilter *aFilter,
2062 BOOL aActiveChanged /* = FALSE */)
2063{
2064 AutoCaller autoCaller(this);
2065 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2066
2067 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2068
2069 if (aFilter->mInList)
2070 {
2071 if (aActiveChanged)
2072 {
2073 // insert/remove the filter from the proxy
2074 if (aFilter->getData().mActive)
2075 {
2076 ComAssertRet(aFilter->getId() == NULL, E_FAIL);
2077 aFilter->getId() = m->pUSBProxyService->insertFilter(&aFilter->getData().mUSBFilter);
2078 }
2079 else
2080 {
2081 ComAssertRet(aFilter->getId() != NULL, E_FAIL);
2082 m->pUSBProxyService->removeFilter(aFilter->getId());
2083 aFilter->getId() = NULL;
2084 }
2085 }
2086 else
2087 {
2088 if (aFilter->getData().mActive)
2089 {
2090 // update the filter in the proxy
2091 ComAssertRet(aFilter->getId() != NULL, E_FAIL);
2092 m->pUSBProxyService->removeFilter(aFilter->getId());
2093 aFilter->getId() = m->pUSBProxyService->insertFilter(&aFilter->getData().mUSBFilter);
2094 }
2095 }
2096
2097 // save the global settings... yeah, on every single filter property change
2098 // for that we should hold only the VirtualBox lock
2099 alock.release();
2100 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
2101 return m->pParent->saveSettings();
2102 }
2103
2104 return S_OK;
2105}
2106
2107
2108/**
2109 * Interface for obtaining a copy of the USBDeviceFilterList,
2110 * used by the USBProxyService.
2111 *
2112 * @param aGlobalFilters Where to put the global filter list copy.
2113 * @param aMachines Where to put the machine vector.
2114 */
2115void Host::getUSBFilters(Host::USBDeviceFilterList *aGlobalFilters)
2116{
2117 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2118
2119 *aGlobalFilters = m->llUSBDeviceFilters;
2120}
2121
2122#endif /* VBOX_WITH_USB */
2123
2124// private methods
2125////////////////////////////////////////////////////////////////////////////////
2126
2127#if defined(RT_OS_SOLARIS) && defined(VBOX_USE_LIBHAL)
2128
2129/**
2130 * Helper function to get the slice number from a device path
2131 *
2132 * @param pszDevLinkPath Pointer to a device path (/dev/(r)dsk/c7d1t0d0s3 etc.)
2133 * @returns Pointer to the slice portion of the given path.
2134 */
2135static char *solarisGetSliceFromPath(const char *pszDevLinkPath)
2136{
2137 char *pszFound = NULL;
2138 char *pszSlice = strrchr(pszDevLinkPath, 's');
2139 char *pszDisk = strrchr(pszDevLinkPath, 'd');
2140 if (pszSlice && pszSlice > pszDisk)
2141 pszFound = pszSlice;
2142 else
2143 pszFound = pszDisk;
2144
2145 if (pszFound && RT_C_IS_DIGIT(pszFound[1]))
2146 return pszFound;
2147
2148 return NULL;
2149}
2150
2151/**
2152 * Walk device links and returns an allocated path for the first one in the snapshot.
2153 *
2154 * @param DevLink Handle to the device link being walked.
2155 * @param pvArg Opaque data containing the pointer to the path.
2156 * @returns Pointer to an allocated device path string.
2157 */
2158static int solarisWalkDevLink(di_devlink_t DevLink, void *pvArg)
2159{
2160 char **ppszPath = (char **)pvArg;
2161 *ppszPath = strdup(di_devlink_path(DevLink));
2162 return DI_WALK_TERMINATE;
2163}
2164
2165/**
2166 * Walk all devices in the system and enumerate CD/DVD drives.
2167 * @param Node Handle to the current node.
2168 * @param pvArg Opaque data (holds list pointer).
2169 * @returns Solaris specific code whether to continue walking or not.
2170 */
2171static int solarisWalkDeviceNodeForDVD(di_node_t Node, void *pvArg)
2172{
2173 PSOLARISDVD *ppDrives = (PSOLARISDVD *)pvArg;
2174
2175 /*
2176 * Check for "removable-media" or "hotpluggable" instead of "SCSI" so that we also include USB CD-ROMs.
2177 * As unfortunately the Solaris drivers only export these common properties.
2178 */
2179 int *pInt = NULL;
2180 if ( di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "removable-media", &pInt) >= 0
2181 || di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "hotpluggable", &pInt) >= 0)
2182 {
2183 if (di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "inquiry-device-type", &pInt) > 0
2184 && ( *pInt == DTYPE_RODIRECT /* CDROM */
2185 || *pInt == DTYPE_OPTICAL)) /* Optical Drive */
2186 {
2187 char *pszProduct = NULL;
2188 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-product-id", &pszProduct) > 0)
2189 {
2190 char *pszVendor = NULL;
2191 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-vendor-id", &pszVendor) > 0)
2192 {
2193 /*
2194 * Found a DVD drive, we need to scan the minor nodes to find the correct
2195 * slice that represents the whole drive. "s2" is always the whole drive for CD/DVDs.
2196 */
2197 int Major = di_driver_major(Node);
2198 di_minor_t Minor = DI_MINOR_NIL;
2199 di_devlink_handle_t DevLink = di_devlink_init(NULL /* name */, 0 /* flags */);
2200 if (DevLink)
2201 {
2202 while ((Minor = di_minor_next(Node, Minor)) != DI_MINOR_NIL)
2203 {
2204 dev_t Dev = di_minor_devt(Minor);
2205 if ( Major != (int)major(Dev)
2206 || di_minor_spectype(Minor) == S_IFBLK
2207 || di_minor_type(Minor) != DDM_MINOR)
2208 {
2209 continue;
2210 }
2211
2212 char *pszMinorPath = di_devfs_minor_path(Minor);
2213 if (!pszMinorPath)
2214 continue;
2215
2216 char *pszDevLinkPath = NULL;
2217 di_devlink_walk(DevLink, NULL, pszMinorPath, DI_PRIMARY_LINK, &pszDevLinkPath, solarisWalkDevLink);
2218 di_devfs_path_free(pszMinorPath);
2219
2220 if (pszDevLinkPath)
2221 {
2222 char *pszSlice = solarisGetSliceFromPath(pszDevLinkPath);
2223 if ( pszSlice && !strcmp(pszSlice, "s2")
2224 && !strncmp(pszDevLinkPath, "/dev/rdsk", sizeof("/dev/rdsk") - 1)) /* We want only raw disks */
2225 {
2226 /*
2227 * We've got a fully qualified DVD drive. Add it to the list.
2228 */
2229 PSOLARISDVD pDrive = (PSOLARISDVD)RTMemAllocZ(sizeof(SOLARISDVD));
2230 if (RT_LIKELY(pDrive))
2231 {
2232 RTStrPrintf(pDrive->szDescription, sizeof(pDrive->szDescription), "%s %s", pszVendor, pszProduct);
2233 RTStrCopy(pDrive->szRawDiskPath, sizeof(pDrive->szRawDiskPath), pszDevLinkPath);
2234 if (*ppDrives)
2235 pDrive->pNext = *ppDrives;
2236 *ppDrives = pDrive;
2237
2238 /* We're not interested in any of the other slices, stop minor nodes traversal. */
2239 free(pszDevLinkPath);
2240 break;
2241 }
2242 }
2243 free(pszDevLinkPath);
2244 }
2245 }
2246 di_devlink_fini(&DevLink);
2247 }
2248 }
2249 }
2250 }
2251 }
2252 return DI_WALK_CONTINUE;
2253}
2254
2255/**
2256 * Solaris specific function to enumerate CD/DVD drives via the device tree.
2257 * Works on Solaris 10 as well as OpenSolaris without depending on libhal.
2258 */
2259void Host::getDVDInfoFromDevTree(std::list<ComObjPtr<Medium> > &list)
2260{
2261 PSOLARISDVD pDrives = NULL;
2262 di_node_t RootNode = di_init("/", DINFOCPYALL);
2263 if (RootNode != DI_NODE_NIL)
2264 di_walk_node(RootNode, DI_WALK_CLDFIRST, &pDrives, solarisWalkDeviceNodeForDVD);
2265
2266 di_fini(RootNode);
2267
2268 while (pDrives)
2269 {
2270 ComObjPtr<Medium> hostDVDDriveObj;
2271 hostDVDDriveObj.createObject();
2272 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(pDrives->szRawDiskPath), Bstr(pDrives->szDescription));
2273 list.push_back(hostDVDDriveObj);
2274
2275 void *pvDrive = pDrives;
2276 pDrives = pDrives->pNext;
2277 RTMemFree(pvDrive);
2278 }
2279}
2280
2281/* Solaris hosts, loading libhal at runtime */
2282
2283/**
2284 * Helper function to query the hal subsystem for information about DVD drives attached to the
2285 * system.
2286 *
2287 * @returns true if information was successfully obtained, false otherwise
2288 * @retval list drives found will be attached to this list
2289 */
2290bool Host::getDVDInfoFromHal(std::list<ComObjPtr<Medium> > &list)
2291{
2292 bool halSuccess = false;
2293 DBusError dbusError;
2294 if (!gLibHalCheckPresence())
2295 return false;
2296 gDBusErrorInit (&dbusError);
2297 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
2298 if (dbusConnection != 0)
2299 {
2300 LibHalContext *halContext = gLibHalCtxNew();
2301 if (halContext != 0)
2302 {
2303 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
2304 {
2305 if (gLibHalCtxInit(halContext, &dbusError))
2306 {
2307 int numDevices;
2308 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
2309 "storage.drive_type", "cdrom",
2310 &numDevices, &dbusError);
2311 if (halDevices != 0)
2312 {
2313 /* Hal is installed and working, so if no devices are reported, assume
2314 that there are none. */
2315 halSuccess = true;
2316 for (int i = 0; i < numDevices; i++)
2317 {
2318 char *devNode = gLibHalDeviceGetPropertyString(halContext,
2319 halDevices[i], "block.device", &dbusError);
2320#ifdef RT_OS_SOLARIS
2321 /* The CD/DVD ioctls work only for raw device nodes. */
2322 char *tmp = getfullrawname(devNode);
2323 gLibHalFreeString(devNode);
2324 devNode = tmp;
2325#endif
2326
2327 if (devNode != 0)
2328 {
2329// if (validateDevice(devNode, true))
2330// {
2331 Utf8Str description;
2332 char *vendor, *product;
2333 /* We do not check the error here, as this field may
2334 not even exist. */
2335 vendor = gLibHalDeviceGetPropertyString(halContext,
2336 halDevices[i], "info.vendor", 0);
2337 product = gLibHalDeviceGetPropertyString(halContext,
2338 halDevices[i], "info.product", &dbusError);
2339 if ((product != 0 && product[0] != 0))
2340 {
2341 if ((vendor != 0) && (vendor[0] != 0))
2342 {
2343 description = Utf8StrFmt ("%s %s",
2344 vendor, product);
2345 }
2346 else
2347 {
2348 description = product;
2349 }
2350 ComObjPtr<Medium> hostDVDDriveObj;
2351 hostDVDDriveObj.createObject();
2352 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
2353 Bstr(devNode), Bstr(description));
2354 list.push_back (hostDVDDriveObj);
2355 }
2356 else
2357 {
2358 if (product == 0)
2359 {
2360 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
2361 halDevices[i], dbusError.name, dbusError.message));
2362 gDBusErrorFree(&dbusError);
2363 }
2364 ComObjPtr<Medium> hostDVDDriveObj;
2365 hostDVDDriveObj.createObject();
2366 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
2367 Bstr(devNode));
2368 list.push_back (hostDVDDriveObj);
2369 }
2370 if (vendor != 0)
2371 {
2372 gLibHalFreeString(vendor);
2373 }
2374 if (product != 0)
2375 {
2376 gLibHalFreeString(product);
2377 }
2378// }
2379// else
2380// {
2381// LogRel(("Host::COMGETTER(DVDDrives): failed to validate the block device %s as a DVD drive\n"));
2382// }
2383#ifndef RT_OS_SOLARIS
2384 gLibHalFreeString(devNode);
2385#else
2386 free(devNode);
2387#endif
2388 }
2389 else
2390 {
2391 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
2392 halDevices[i], dbusError.name, dbusError.message));
2393 gDBusErrorFree(&dbusError);
2394 }
2395 }
2396 gLibHalFreeStringArray(halDevices);
2397 }
2398 else
2399 {
2400 LogRel(("Host::COMGETTER(DVDDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2401 gDBusErrorFree(&dbusError);
2402 }
2403 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
2404 {
2405 LogRel(("Host::COMGETTER(DVDDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2406 gDBusErrorFree(&dbusError);
2407 }
2408 }
2409 else
2410 {
2411 LogRel(("Host::COMGETTER(DVDDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2412 gDBusErrorFree(&dbusError);
2413 }
2414 gLibHalCtxFree(halContext);
2415 }
2416 else
2417 {
2418 LogRel(("Host::COMGETTER(DVDDrives): failed to set libhal connection to dbus.\n"));
2419 }
2420 }
2421 else
2422 {
2423 LogRel(("Host::COMGETTER(DVDDrives): failed to get a libhal context - out of memory?\n"));
2424 }
2425 gDBusConnectionUnref(dbusConnection);
2426 }
2427 else
2428 {
2429 LogRel(("Host::COMGETTER(DVDDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2430 gDBusErrorFree(&dbusError);
2431 }
2432 return halSuccess;
2433}
2434
2435
2436/**
2437 * Helper function to query the hal subsystem for information about floppy drives attached to the
2438 * system.
2439 *
2440 * @returns true if information was successfully obtained, false otherwise
2441 * @retval list drives found will be attached to this list
2442 */
2443bool Host::getFloppyInfoFromHal(std::list< ComObjPtr<Medium> > &list)
2444{
2445 bool halSuccess = false;
2446 DBusError dbusError;
2447 if (!gLibHalCheckPresence())
2448 return false;
2449 gDBusErrorInit (&dbusError);
2450 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
2451 if (dbusConnection != 0)
2452 {
2453 LibHalContext *halContext = gLibHalCtxNew();
2454 if (halContext != 0)
2455 {
2456 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
2457 {
2458 if (gLibHalCtxInit(halContext, &dbusError))
2459 {
2460 int numDevices;
2461 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
2462 "storage.drive_type", "floppy",
2463 &numDevices, &dbusError);
2464 if (halDevices != 0)
2465 {
2466 /* Hal is installed and working, so if no devices are reported, assume
2467 that there are none. */
2468 halSuccess = true;
2469 for (int i = 0; i < numDevices; i++)
2470 {
2471 char *driveType = gLibHalDeviceGetPropertyString(halContext,
2472 halDevices[i], "storage.drive_type", 0);
2473 if (driveType != 0)
2474 {
2475 if (strcmp(driveType, "floppy") != 0)
2476 {
2477 gLibHalFreeString(driveType);
2478 continue;
2479 }
2480 gLibHalFreeString(driveType);
2481 }
2482 else
2483 {
2484 /* An error occurred. The attribute "storage.drive_type"
2485 probably didn't exist. */
2486 continue;
2487 }
2488 char *devNode = gLibHalDeviceGetPropertyString(halContext,
2489 halDevices[i], "block.device", &dbusError);
2490 if (devNode != 0)
2491 {
2492// if (validateDevice(devNode, false))
2493// {
2494 Utf8Str description;
2495 char *vendor, *product;
2496 /* We do not check the error here, as this field may
2497 not even exist. */
2498 vendor = gLibHalDeviceGetPropertyString(halContext,
2499 halDevices[i], "info.vendor", 0);
2500 product = gLibHalDeviceGetPropertyString(halContext,
2501 halDevices[i], "info.product", &dbusError);
2502 if ((product != 0) && (product[0] != 0))
2503 {
2504 if ((vendor != 0) && (vendor[0] != 0))
2505 {
2506 description = Utf8StrFmt ("%s %s",
2507 vendor, product);
2508 }
2509 else
2510 {
2511 description = product;
2512 }
2513 ComObjPtr<Medium> hostFloppyDrive;
2514 hostFloppyDrive.createObject();
2515 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
2516 Bstr(devNode), Bstr(description));
2517 list.push_back (hostFloppyDrive);
2518 }
2519 else
2520 {
2521 if (product == 0)
2522 {
2523 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
2524 halDevices[i], dbusError.name, dbusError.message));
2525 gDBusErrorFree(&dbusError);
2526 }
2527 ComObjPtr<Medium> hostFloppyDrive;
2528 hostFloppyDrive.createObject();
2529 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
2530 Bstr(devNode));
2531 list.push_back (hostFloppyDrive);
2532 }
2533 if (vendor != 0)
2534 {
2535 gLibHalFreeString(vendor);
2536 }
2537 if (product != 0)
2538 {
2539 gLibHalFreeString(product);
2540 }
2541// }
2542// else
2543// {
2544// LogRel(("Host::COMGETTER(FloppyDrives): failed to validate the block device %s as a floppy drive\n"));
2545// }
2546 gLibHalFreeString(devNode);
2547 }
2548 else
2549 {
2550 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
2551 halDevices[i], dbusError.name, dbusError.message));
2552 gDBusErrorFree(&dbusError);
2553 }
2554 }
2555 gLibHalFreeStringArray(halDevices);
2556 }
2557 else
2558 {
2559 LogRel(("Host::COMGETTER(FloppyDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2560 gDBusErrorFree(&dbusError);
2561 }
2562 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
2563 {
2564 LogRel(("Host::COMGETTER(FloppyDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2565 gDBusErrorFree(&dbusError);
2566 }
2567 }
2568 else
2569 {
2570 LogRel(("Host::COMGETTER(FloppyDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2571 gDBusErrorFree(&dbusError);
2572 }
2573 gLibHalCtxFree(halContext);
2574 }
2575 else
2576 {
2577 LogRel(("Host::COMGETTER(FloppyDrives): failed to set libhal connection to dbus.\n"));
2578 }
2579 }
2580 else
2581 {
2582 LogRel(("Host::COMGETTER(FloppyDrives): failed to get a libhal context - out of memory?\n"));
2583 }
2584 gDBusConnectionUnref(dbusConnection);
2585 }
2586 else
2587 {
2588 LogRel(("Host::COMGETTER(FloppyDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2589 gDBusErrorFree(&dbusError);
2590 }
2591 return halSuccess;
2592}
2593#endif /* RT_OS_SOLARIS and VBOX_USE_HAL */
2594
2595/** @todo get rid of dead code below - RT_OS_SOLARIS and RT_OS_LINUX are never both set */
2596#if defined(RT_OS_SOLARIS)
2597
2598/**
2599 * Helper function to parse the given mount file and add found entries
2600 */
2601void Host::parseMountTable(char *mountTable, std::list< ComObjPtr<Medium> > &list)
2602{
2603#ifdef RT_OS_LINUX
2604 FILE *mtab = setmntent(mountTable, "r");
2605 if (mtab)
2606 {
2607 struct mntent *mntent;
2608 char *mnt_type;
2609 char *mnt_dev;
2610 char *tmp;
2611 while ((mntent = getmntent(mtab)))
2612 {
2613 mnt_type = (char*)malloc(strlen(mntent->mnt_type) + 1);
2614 mnt_dev = (char*)malloc(strlen(mntent->mnt_fsname) + 1);
2615 strcpy(mnt_type, mntent->mnt_type);
2616 strcpy(mnt_dev, mntent->mnt_fsname);
2617 // supermount fs case
2618 if (strcmp(mnt_type, "supermount") == 0)
2619 {
2620 tmp = strstr(mntent->mnt_opts, "fs=");
2621 if (tmp)
2622 {
2623 free(mnt_type);
2624 mnt_type = strdup(tmp + strlen("fs="));
2625 if (mnt_type)
2626 {
2627 tmp = strchr(mnt_type, ',');
2628 if (tmp)
2629 *tmp = '\0';
2630 }
2631 }
2632 tmp = strstr(mntent->mnt_opts, "dev=");
2633 if (tmp)
2634 {
2635 free(mnt_dev);
2636 mnt_dev = strdup(tmp + strlen("dev="));
2637 if (mnt_dev)
2638 {
2639 tmp = strchr(mnt_dev, ',');
2640 if (tmp)
2641 *tmp = '\0';
2642 }
2643 }
2644 }
2645 // use strstr here to cover things fs types like "udf,iso9660"
2646 if (strstr(mnt_type, "iso9660") == 0)
2647 {
2648 /** @todo check whether we've already got the drive in our list! */
2649 if (validateDevice(mnt_dev, true))
2650 {
2651 ComObjPtr<Medium> hostDVDDriveObj;
2652 hostDVDDriveObj.createObject();
2653 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(mnt_dev));
2654 list.push_back (hostDVDDriveObj);
2655 }
2656 }
2657 free(mnt_dev);
2658 free(mnt_type);
2659 }
2660 endmntent(mtab);
2661 }
2662#else // RT_OS_SOLARIS
2663 FILE *mntFile = fopen(mountTable, "r");
2664 if (mntFile)
2665 {
2666 struct mnttab mntTab;
2667 while (getmntent(mntFile, &mntTab) == 0)
2668 {
2669 const char *mountName = mntTab.mnt_special;
2670 const char *mountPoint = mntTab.mnt_mountp;
2671 const char *mountFSType = mntTab.mnt_fstype;
2672 if (mountName && mountPoint && mountFSType)
2673 {
2674 // skip devices we are not interested in
2675 if ((*mountName && mountName[0] == '/') && // skip 'fake' devices (like -hosts, proc, fd, swap)
2676 (*mountFSType && (strncmp(mountFSType, "devfs", 5) != 0 && // skip devfs (i.e. /devices)
2677 strncmp(mountFSType, "dev", 3) != 0 && // skip dev (i.e. /dev)
2678 strncmp(mountFSType, "lofs", 4) != 0))) // skip loop-back file-system (lofs)
2679 {
2680 char *rawDevName = getfullrawname((char *)mountName);
2681 if (validateDevice(rawDevName, true))
2682 {
2683 ComObjPtr<Medium> hostDVDDriveObj;
2684 hostDVDDriveObj.createObject();
2685 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(rawDevName));
2686 list.push_back (hostDVDDriveObj);
2687 }
2688 free(rawDevName);
2689 }
2690 }
2691 }
2692
2693 fclose(mntFile);
2694 }
2695#endif
2696}
2697
2698/**
2699 * Helper function to check whether the given device node is a valid drive
2700 */
2701bool Host::validateDevice(const char *deviceNode, bool isCDROM)
2702{
2703 struct stat statInfo;
2704 bool retValue = false;
2705
2706 // sanity check
2707 if (!deviceNode)
2708 {
2709 return false;
2710 }
2711
2712 // first a simple stat() call
2713 if (stat(deviceNode, &statInfo) < 0)
2714 {
2715 return false;
2716 }
2717 else
2718 {
2719 if (isCDROM)
2720 {
2721 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2722 {
2723 int fileHandle;
2724 // now try to open the device
2725 fileHandle = open(deviceNode, O_RDONLY | O_NONBLOCK, 0);
2726 if (fileHandle >= 0)
2727 {
2728 cdrom_subchnl cdChannelInfo;
2729 cdChannelInfo.cdsc_format = CDROM_MSF;
2730 // this call will finally reveal the whole truth
2731#ifdef RT_OS_LINUX
2732 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2733 (errno == EIO) || (errno == ENOENT) ||
2734 (errno == EINVAL) || (errno == ENOMEDIUM))
2735#else
2736 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2737 (errno == EIO) || (errno == ENOENT) ||
2738 (errno == EINVAL))
2739#endif
2740 {
2741 retValue = true;
2742 }
2743 close(fileHandle);
2744 }
2745 }
2746 } else
2747 {
2748 // floppy case
2749 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2750 {
2751 /// @todo do some more testing, maybe a nice IOCTL!
2752 retValue = true;
2753 }
2754 }
2755 }
2756 return retValue;
2757}
2758#endif // RT_OS_SOLARIS
2759
2760#ifdef VBOX_WITH_USB
2761/**
2762 * Checks for the presence and status of the USB Proxy Service.
2763 * Returns S_OK when the Proxy is present and OK, VBOX_E_HOST_ERROR (as a
2764 * warning) if the proxy service is not available due to the way the host is
2765 * configured (at present, that means that usbfs and hal/DBus are not
2766 * available on a Linux host) or E_FAIL and a corresponding error message
2767 * otherwise. Intended to be used by methods that rely on the Proxy Service
2768 * availability.
2769 *
2770 * @note This method may return a warning result code. It is recommended to use
2771 * MultiError to store the return value.
2772 *
2773 * @note Locks this object for reading.
2774 */
2775HRESULT Host::checkUSBProxyService()
2776{
2777 AutoCaller autoCaller(this);
2778 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2779
2780 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2781
2782 AssertReturn(m->pUSBProxyService, E_FAIL);
2783 if (!m->pUSBProxyService->isActive())
2784 {
2785 /* disable the USB controller completely to avoid assertions if the
2786 * USB proxy service could not start. */
2787
2788 switch (m->pUSBProxyService->getLastError())
2789 {
2790 case VERR_FILE_NOT_FOUND: /** @todo what does this mean? */
2791 return setWarning(E_FAIL,
2792 tr("Could not load the Host USB Proxy Service (VERR_FILE_NOT_FOUND). The service might not be installed on the host computer"));
2793 case VERR_VUSB_USB_DEVICE_PERMISSION:
2794 return setWarning(E_FAIL,
2795 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"));
2796 case VERR_VUSB_USBFS_PERMISSION:
2797 return setWarning(E_FAIL,
2798 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"));
2799 case VINF_SUCCESS:
2800 return setWarning(E_FAIL,
2801 tr("The USB Proxy Service has not yet been ported to this host"));
2802 default:
2803 return setWarning (E_FAIL, "%s: %Rrc",
2804 tr ("Could not load the Host USB Proxy service"),
2805 m->pUSBProxyService->getLastError());
2806 }
2807 }
2808
2809 return S_OK;
2810}
2811#endif /* VBOX_WITH_USB */
2812
2813#ifdef VBOX_WITH_RESOURCE_USAGE_API
2814
2815void Host::registerMetrics(PerformanceCollector *aCollector)
2816{
2817 pm::CollectorHAL *hal = aCollector->getHAL();
2818 /* Create sub metrics */
2819 pm::SubMetric *cpuLoadUser = new pm::SubMetric("CPU/Load/User",
2820 "Percentage of processor time spent in user mode.");
2821 pm::SubMetric *cpuLoadKernel = new pm::SubMetric("CPU/Load/Kernel",
2822 "Percentage of processor time spent in kernel mode.");
2823 pm::SubMetric *cpuLoadIdle = new pm::SubMetric("CPU/Load/Idle",
2824 "Percentage of processor time spent idling.");
2825 pm::SubMetric *cpuMhzSM = new pm::SubMetric("CPU/MHz",
2826 "Average of current frequency of all processors.");
2827 pm::SubMetric *ramUsageTotal = new pm::SubMetric("RAM/Usage/Total",
2828 "Total physical memory installed.");
2829 pm::SubMetric *ramUsageUsed = new pm::SubMetric("RAM/Usage/Used",
2830 "Physical memory currently occupied.");
2831 pm::SubMetric *ramUsageFree = new pm::SubMetric("RAM/Usage/Free",
2832 "Physical memory currently available to applications.");
2833 pm::SubMetric *ramVMMUsed = new pm::SubMetric("RAM/VMM/Used",
2834 "Total physical memory used by the hypervisor.");
2835 pm::SubMetric *ramVMMFree = new pm::SubMetric("RAM/VMM/Free",
2836 "Total physical memory free inside the hypervisor.");
2837 pm::SubMetric *ramVMMBallooned = new pm::SubMetric("RAM/VMM/Ballooned",
2838 "Total physical memory ballooned by the hypervisor.");
2839 pm::SubMetric *ramVMMShared = new pm::SubMetric("RAM/VMM/Shared",
2840 "Total physical memory shared between VMs.");
2841
2842
2843 /* Create and register base metrics */
2844 IUnknown *objptr;
2845 ComObjPtr<Host> tmp = this;
2846 tmp.queryInterfaceTo(&objptr);
2847 pm::BaseMetric *cpuLoad = new pm::HostCpuLoadRaw(hal, objptr, cpuLoadUser, cpuLoadKernel,
2848 cpuLoadIdle);
2849 aCollector->registerBaseMetric (cpuLoad);
2850 pm::BaseMetric *cpuMhz = new pm::HostCpuMhz(hal, objptr, cpuMhzSM);
2851 aCollector->registerBaseMetric (cpuMhz);
2852 pm::BaseMetric *ramUsage = new pm::HostRamUsage(hal, objptr,
2853 ramUsageTotal,
2854 ramUsageUsed,
2855 ramUsageFree);
2856 aCollector->registerBaseMetric (ramUsage);
2857 pm::BaseMetric *ramVmm = new pm::HostRamVmm(aCollector->getGuestManager(), objptr,
2858 ramVMMUsed,
2859 ramVMMFree,
2860 ramVMMBallooned,
2861 ramVMMShared);
2862 aCollector->registerBaseMetric (ramVmm);
2863
2864 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser, 0));
2865 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
2866 new pm::AggregateAvg()));
2867 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
2868 new pm::AggregateMin()));
2869 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
2870 new pm::AggregateMax()));
2871
2872 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel, 0));
2873 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
2874 new pm::AggregateAvg()));
2875 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
2876 new pm::AggregateMin()));
2877 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
2878 new pm::AggregateMax()));
2879
2880 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle, 0));
2881 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
2882 new pm::AggregateAvg()));
2883 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
2884 new pm::AggregateMin()));
2885 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
2886 new pm::AggregateMax()));
2887
2888 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM, 0));
2889 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
2890 new pm::AggregateAvg()));
2891 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
2892 new pm::AggregateMin()));
2893 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
2894 new pm::AggregateMax()));
2895
2896 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal, 0));
2897 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
2898 new pm::AggregateAvg()));
2899 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
2900 new pm::AggregateMin()));
2901 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
2902 new pm::AggregateMax()));
2903
2904 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed, 0));
2905 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
2906 new pm::AggregateAvg()));
2907 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
2908 new pm::AggregateMin()));
2909 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
2910 new pm::AggregateMax()));
2911
2912 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree, 0));
2913 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
2914 new pm::AggregateAvg()));
2915 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
2916 new pm::AggregateMin()));
2917 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
2918 new pm::AggregateMax()));
2919
2920 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed, 0));
2921 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
2922 new pm::AggregateAvg()));
2923 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
2924 new pm::AggregateMin()));
2925 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
2926 new pm::AggregateMax()));
2927
2928 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree, 0));
2929 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
2930 new pm::AggregateAvg()));
2931 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
2932 new pm::AggregateMin()));
2933 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
2934 new pm::AggregateMax()));
2935
2936 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned, 0));
2937 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
2938 new pm::AggregateAvg()));
2939 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
2940 new pm::AggregateMin()));
2941 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
2942 new pm::AggregateMax()));
2943
2944 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared, 0));
2945 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
2946 new pm::AggregateAvg()));
2947 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
2948 new pm::AggregateMin()));
2949 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
2950 new pm::AggregateMax()));
2951}
2952
2953void Host::unregisterMetrics (PerformanceCollector *aCollector)
2954{
2955 aCollector->unregisterMetricsFor(this);
2956 aCollector->unregisterBaseMetricsFor(this);
2957}
2958
2959
2960/* static */
2961void Host::generateMACAddress(Utf8Str &mac)
2962{
2963 /*
2964 * Our strategy is as follows: the first three bytes are our fixed
2965 * vendor ID (080027). The remaining 3 bytes will be taken from the
2966 * start of a GUID. This is a fairly safe algorithm.
2967 */
2968 Guid guid;
2969 guid.create();
2970 mac = Utf8StrFmt("080027%02X%02X%02X",
2971 guid.raw()->au8[0], guid.raw()->au8[1], guid.raw()->au8[2]);
2972}
2973
2974#endif /* VBOX_WITH_RESOURCE_USAGE_API */
2975
2976/* 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