VirtualBox

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

Last change on this file since 43541 was 43525, checked in by vboxsync, 12 years ago

Main/Metrics: build fix

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