VirtualBox

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

Last change on this file since 42178 was 42024, checked in by vboxsync, 13 years ago

VMM: RDTSCP support on Intel. Segregated some common CPU features from the AMD superset into Extended features as they're now available on Intel too.

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