VirtualBox

source: vbox/trunk/src/VBox/Main/HostImpl.cpp@ 28770

Last change on this file since 28770 was 28583, checked in by vboxsync, 15 years ago

Dropped redundant code for listing network interfaces on Solaris

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 82.6 KB
Line 
1/* $Id: HostImpl.cpp 28583 2010-04-22 09:31:09Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation: Host
4 */
5
6/*
7 * Copyright (C) 2006-2010 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22#define __STDC_LIMIT_MACROS
23#define __STDC_CONSTANT_MACROS
24
25#include "HostImpl.h"
26
27#ifdef VBOX_WITH_USB
28# include "HostUSBDeviceImpl.h"
29# include "USBDeviceFilterImpl.h"
30# include "USBProxyService.h"
31#endif // VBOX_WITH_USB
32
33#include "HostNetworkInterfaceImpl.h"
34#include "MachineImpl.h"
35#include "AutoCaller.h"
36#include "Logging.h"
37#include "Performance.h"
38
39#include "MediumImpl.h"
40#include "HostPower.h"
41
42#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
43# include <HostHardwareLinux.h>
44#endif
45
46#ifdef VBOX_WITH_RESOURCE_USAGE_API
47# include "PerformanceImpl.h"
48#endif /* VBOX_WITH_RESOURCE_USAGE_API */
49
50#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
51# include <VBox/WinNetConfig.h>
52#endif /* #if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT) */
53
54#ifdef RT_OS_LINUX
55# include <sys/ioctl.h>
56# include <errno.h>
57# include <net/if.h>
58# include <net/if_arp.h>
59#endif /* RT_OS_LINUX */
60
61#ifdef RT_OS_SOLARIS
62# include <fcntl.h>
63# include <unistd.h>
64# include <stropts.h>
65# include <errno.h>
66# include <limits.h>
67# include <stdio.h>
68# ifdef VBOX_SOLARIS_NSL_RESOLVED
69# include <libdevinfo.h>
70# endif
71# include <net/if.h>
72# include <sys/socket.h>
73# include <sys/sockio.h>
74# include <net/if_arp.h>
75# include <net/if.h>
76# include <sys/types.h>
77# include <sys/stat.h>
78# include <sys/cdio.h>
79# include <sys/dkio.h>
80# include <sys/mnttab.h>
81# include <sys/mntent.h>
82/* Dynamic loading of libhal on Solaris hosts */
83# ifdef VBOX_USE_LIBHAL
84# include "vbox-libhal.h"
85extern "C" char *getfullrawname(char *);
86# endif
87# include "solaris/DynLoadLibSolaris.h"
88#endif /* RT_OS_SOLARIS */
89
90#ifdef RT_OS_WINDOWS
91# define _WIN32_DCOM
92# include <windows.h>
93# include <shellapi.h>
94# define INITGUID
95# include <guiddef.h>
96# include <devguid.h>
97# include <objbase.h>
98//# include <setupapi.h>
99# include <shlobj.h>
100# include <cfgmgr32.h>
101
102#endif /* RT_OS_WINDOWS */
103
104#ifdef RT_OS_DARWIN
105# include "darwin/iokit.h"
106#endif
107
108#ifdef VBOX_WITH_CROGL
109extern bool is3DAccelerationSupported();
110#endif /* VBOX_WITH_CROGL */
111
112#include <iprt/asm.h>
113#include <iprt/string.h>
114#include <iprt/mp.h>
115#include <iprt/time.h>
116#include <iprt/param.h>
117#include <iprt/env.h>
118#include <iprt/mem.h>
119#include <iprt/system.h>
120#ifdef RT_OS_SOLARIS
121# include <iprt/path.h>
122# include <iprt/ctype.h>
123#endif
124#ifdef VBOX_WITH_HOSTNETIF_API
125#include "netif.h"
126#endif
127
128/* XXX Solaris: definitions in /usr/include/sys/regset.h clash with hwacc_svm.h */
129#undef DS
130#undef ES
131#undef CS
132#undef SS
133#undef FS
134#undef GS
135
136#include <VBox/usb.h>
137#include <VBox/x86.h>
138#include <VBox/hwacc_svm.h>
139#include <VBox/err.h>
140#include <VBox/settings.h>
141#include <VBox/sup.h>
142
143#include <stdio.h>
144
145#include <algorithm>
146
147
148////////////////////////////////////////////////////////////////////////////////
149//
150// Host private data definition
151//
152////////////////////////////////////////////////////////////////////////////////
153
154struct Host::Data
155{
156 Data()
157#ifdef VBOX_WITH_USB
158 : usbListsLock(LOCKCLASS_USBLIST)
159#endif
160 {};
161
162 VirtualBox *pParent;
163
164#ifdef VBOX_WITH_USB
165 WriteLockHandle usbListsLock; // protects the below two lists
166
167 USBDeviceFilterList llChildren; // all USB device filters
168 USBDeviceFilterList llUSBDeviceFilters; // USB device filters in use by the USB proxy service
169
170 /** Pointer to the USBProxyService object. */
171 USBProxyService *pUSBProxyService;
172#endif /* VBOX_WITH_USB */
173
174#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
175 /** Object with information about host drives */
176 VBoxMainDriveInfo hostDrives;
177#endif
178 /* Features that can be queried with GetProcessorFeature */
179 BOOL fVTSupported,
180 fLongModeSupported,
181 fPAESupported,
182 fNestedPagingSupported;
183
184 /* 3D hardware acceleration supported? */
185 BOOL f3DAccelerationSupported;
186
187 HostPowerService *pHostPowerService;
188};
189
190
191////////////////////////////////////////////////////////////////////////////////
192//
193// Constructor / destructor
194//
195////////////////////////////////////////////////////////////////////////////////
196
197HRESULT Host::FinalConstruct()
198{
199 return S_OK;
200}
201
202void Host::FinalRelease()
203{
204 uninit();
205}
206
207/**
208 * Initializes the host object.
209 *
210 * @param aParent VirtualBox parent object.
211 */
212HRESULT Host::init(VirtualBox *aParent)
213{
214 LogFlowThisFunc(("aParent=%p\n", aParent));
215
216 /* Enclose the state transition NotReady->InInit->Ready */
217 AutoInitSpan autoInitSpan(this);
218 AssertReturn(autoInitSpan.isOk(), E_FAIL);
219
220 m = new Data();
221
222 m->pParent = aParent;
223
224#ifdef VBOX_WITH_USB
225 /*
226 * Create and initialize the USB Proxy Service.
227 */
228# if defined (RT_OS_DARWIN)
229 m->pUSBProxyService = new USBProxyServiceDarwin(this);
230# elif defined (RT_OS_LINUX)
231 m->pUSBProxyService = new USBProxyServiceLinux(this);
232# elif defined (RT_OS_OS2)
233 m->pUSBProxyService = new USBProxyServiceOs2 (this);
234# elif defined (RT_OS_SOLARIS)
235 m->pUSBProxyService = new USBProxyServiceSolaris(this);
236# elif defined (RT_OS_WINDOWS)
237 m->pUSBProxyService = new USBProxyServiceWindows(this);
238# elif defined (RT_OS_FREEBSD)
239 m->pUSBProxyService = new USBProxyServiceFreeBSD(this);
240# else
241 m->pUSBProxyService = new USBProxyService(this);
242# endif
243 HRESULT hrc = m->pUSBProxyService->init();
244 AssertComRCReturn(hrc, hrc);
245#endif /* VBOX_WITH_USB */
246
247#ifdef VBOX_WITH_RESOURCE_USAGE_API
248 registerMetrics(aParent->performanceCollector());
249#endif /* VBOX_WITH_RESOURCE_USAGE_API */
250
251#if defined (RT_OS_WINDOWS)
252 m->pHostPowerService = new HostPowerServiceWin(m->pParent);
253#elif defined (RT_OS_DARWIN)
254 m->pHostPowerService = new HostPowerServiceDarwin(m->pParent);
255#else
256 m->pHostPowerService = new HostPowerService(m->pParent);
257#endif
258
259 /* Cache the features reported by GetProcessorFeature. */
260 m->fVTSupported = false;
261 m->fLongModeSupported = false;
262 m->fPAESupported = false;
263 m->fNestedPagingSupported = false;
264
265 if (ASMHasCpuId())
266 {
267 uint32_t u32FeaturesECX;
268 uint32_t u32Dummy;
269 uint32_t u32FeaturesEDX;
270 uint32_t u32VendorEBX, u32VendorECX, u32VendorEDX, u32AMDFeatureEDX, u32AMDFeatureECX;
271
272 ASMCpuId(0, &u32Dummy, &u32VendorEBX, &u32VendorECX, &u32VendorEDX);
273 ASMCpuId(1, &u32Dummy, &u32Dummy, &u32FeaturesECX, &u32FeaturesEDX);
274 /* Query AMD features. */
275 ASMCpuId(0x80000001, &u32Dummy, &u32Dummy, &u32AMDFeatureECX, &u32AMDFeatureEDX);
276
277 m->fLongModeSupported = !!(u32AMDFeatureEDX & X86_CPUID_AMD_FEATURE_EDX_LONG_MODE);
278 m->fPAESupported = !!(u32FeaturesEDX & X86_CPUID_FEATURE_EDX_PAE);
279
280 if ( u32VendorEBX == X86_CPUID_VENDOR_INTEL_EBX
281 && u32VendorECX == X86_CPUID_VENDOR_INTEL_ECX
282 && u32VendorEDX == X86_CPUID_VENDOR_INTEL_EDX
283 )
284 {
285 if ( (u32FeaturesECX & X86_CPUID_FEATURE_ECX_VMX)
286 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR)
287 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR)
288 )
289 {
290 int rc = SUPR3QueryVTxSupported();
291 if (RT_SUCCESS(rc))
292 m->fVTSupported = true;
293 }
294 }
295 else
296 if ( u32VendorEBX == X86_CPUID_VENDOR_AMD_EBX
297 && u32VendorECX == X86_CPUID_VENDOR_AMD_ECX
298 && u32VendorEDX == X86_CPUID_VENDOR_AMD_EDX
299 )
300 {
301 if ( (u32AMDFeatureECX & X86_CPUID_AMD_FEATURE_ECX_SVM)
302 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR)
303 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR)
304 )
305 {
306 uint32_t u32SVMFeatureEDX;
307
308 m->fVTSupported = true;
309
310 /* Query AMD features. */
311 ASMCpuId(0x8000000A, &u32Dummy, &u32Dummy, &u32Dummy, &u32SVMFeatureEDX);
312 if (u32SVMFeatureEDX & AMD_CPUID_SVM_FEATURE_EDX_NESTED_PAGING)
313 m->fNestedPagingSupported = true;
314 }
315 }
316 }
317
318#if 0 /* needs testing */
319 if (m->fVTSupported)
320 {
321 uint32_t u32Caps = 0;
322
323 int rc = SUPR3QueryVTCaps(&u32Caps);
324 if (RT_SUCCESS(rc))
325 {
326 if (u32Caps & SUPVTCAPS_NESTED_PAGING)
327 m->fNestedPagingSupported = true;
328 }
329 /* else @todo; report BIOS trouble in some way. */
330 }
331#endif
332
333 /* Test for 3D hardware acceleration support */
334 m->f3DAccelerationSupported = false;
335
336#ifdef VBOX_WITH_CROGL
337 m->f3DAccelerationSupported = is3DAccelerationSupported();
338#endif /* VBOX_WITH_CROGL */
339
340 /* Confirm a successful initialization */
341 autoInitSpan.setSucceeded();
342
343 return S_OK;
344}
345
346/**
347 * Uninitializes the host object and sets the ready flag to FALSE.
348 * Called either from FinalRelease() or by the parent when it gets destroyed.
349 */
350void Host::uninit()
351{
352 LogFlowThisFunc(("\n"));
353
354 /* Enclose the state transition Ready->InUninit->NotReady */
355 AutoUninitSpan autoUninitSpan(this);
356 if (autoUninitSpan.uninitDone())
357 return;
358
359#ifdef VBOX_WITH_RESOURCE_USAGE_API
360 unregisterMetrics (m->pParent->performanceCollector());
361#endif /* VBOX_WITH_RESOURCE_USAGE_API */
362
363#ifdef VBOX_WITH_USB
364 /* wait for USB proxy service to terminate before we uninit all USB
365 * devices */
366 LogFlowThisFunc(("Stopping USB proxy service...\n"));
367 delete m->pUSBProxyService;
368 m->pUSBProxyService = NULL;
369 LogFlowThisFunc(("Done stopping USB proxy service.\n"));
370#endif
371
372 delete m->pHostPowerService;
373
374#ifdef VBOX_WITH_USB
375 /* uninit all USB device filters still referenced by clients
376 * Note! HostUSBDeviceFilter::uninit() will modify llChildren. */
377 while (!m->llChildren.empty())
378 {
379 ComObjPtr<HostUSBDeviceFilter> &pChild = m->llChildren.front();
380 pChild->uninit();
381 }
382
383 m->llUSBDeviceFilters.clear();
384#endif
385
386 delete m;
387 m = NULL;
388}
389
390////////////////////////////////////////////////////////////////////////////////
391//
392// ISnapshot public methods
393//
394////////////////////////////////////////////////////////////////////////////////
395
396/**
397 * Returns a list of host DVD drives.
398 *
399 * @returns COM status code
400 * @param drives address of result pointer
401 */
402STDMETHODIMP Host::COMGETTER(DVDDrives)(ComSafeArrayOut(IMedium *, aDrives))
403{
404 CheckComArgOutSafeArrayPointerValid(aDrives);
405
406 AutoCaller autoCaller(this);
407 if (FAILED(autoCaller.rc())) return autoCaller.rc();
408
409 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
410
411 MediaList list;
412 HRESULT rc = getDVDDrives(list);
413 if (SUCCEEDED(rc))
414 {
415 SafeIfaceArray<IMedium> array(list);
416 array.detachTo(ComSafeArrayOutArg(aDrives));
417 }
418
419 return rc;
420}
421
422/**
423 * Returns a list of host floppy drives.
424 *
425 * @returns COM status code
426 * @param drives address of result pointer
427 */
428STDMETHODIMP Host::COMGETTER(FloppyDrives)(ComSafeArrayOut(IMedium *, aDrives))
429{
430 CheckComArgOutPointerValid(aDrives);
431
432 AutoCaller autoCaller(this);
433 if (FAILED(autoCaller.rc())) return autoCaller.rc();
434
435 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
436
437 MediaList list;
438 HRESULT rc = getFloppyDrives(list);
439 if (SUCCEEDED(rc))
440 {
441 SafeIfaceArray<IMedium> collection(list);
442 collection.detachTo(ComSafeArrayOutArg(aDrives));
443 }
444
445 return rc;
446}
447
448
449#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
450# define VBOX_APP_NAME L"VirtualBox"
451
452static int vboxNetWinAddComponent(std::list< ComObjPtr<HostNetworkInterface> > *pPist,
453 INetCfgComponent *pncc)
454{
455 LPWSTR lpszName;
456 GUID IfGuid;
457 HRESULT hr;
458 int rc = VERR_GENERAL_FAILURE;
459
460 hr = pncc->GetDisplayName( &lpszName );
461 Assert(hr == S_OK);
462 if (hr == S_OK)
463 {
464 Bstr name((CBSTR)lpszName);
465
466 hr = pncc->GetInstanceGuid(&IfGuid);
467 Assert(hr == S_OK);
468 if (hr == S_OK)
469 {
470 /* create a new object and add it to the list */
471 ComObjPtr<HostNetworkInterface> iface;
472 iface.createObject();
473 /* remove the curly bracket at the end */
474 if (SUCCEEDED(iface->init (name, Guid (IfGuid), HostNetworkInterfaceType_Bridged)))
475 {
476// iface->setVirtualBox(m->pParent);
477 pPist->push_back(iface);
478 rc = VINF_SUCCESS;
479 }
480 else
481 {
482 Assert(0);
483 }
484 }
485 CoTaskMemFree(lpszName);
486 }
487
488 return rc;
489}
490#endif /* defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT) */
491
492/**
493 * Returns a list of host network interfaces.
494 *
495 * @returns COM status code
496 * @param drives address of result pointer
497 */
498STDMETHODIMP Host::COMGETTER(NetworkInterfaces)(ComSafeArrayOut(IHostNetworkInterface*, aNetworkInterfaces))
499{
500#if defined(RT_OS_WINDOWS) || defined(VBOX_WITH_NETFLT) /*|| defined(RT_OS_OS2)*/
501 if (ComSafeArrayOutIsNull(aNetworkInterfaces))
502 return E_POINTER;
503
504 AutoCaller autoCaller(this);
505 if (FAILED(autoCaller.rc())) return autoCaller.rc();
506
507 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
508
509 std::list <ComObjPtr<HostNetworkInterface> > list;
510
511# ifdef VBOX_WITH_HOSTNETIF_API
512 int rc = NetIfList(list);
513 if (rc)
514 {
515 Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
516 }
517# else
518
519# if defined(RT_OS_DARWIN)
520 PDARWINETHERNIC pEtherNICs = DarwinGetEthernetControllers();
521 while (pEtherNICs)
522 {
523 ComObjPtr<HostNetworkInterface> IfObj;
524 IfObj.createObject();
525 if (SUCCEEDED(IfObj->init(Bstr(pEtherNICs->szName), Guid(pEtherNICs->Uuid), HostNetworkInterfaceType_Bridged)))
526 list.push_back(IfObj);
527
528 /* next, free current */
529 void *pvFree = pEtherNICs;
530 pEtherNICs = pEtherNICs->pNext;
531 RTMemFree(pvFree);
532 }
533
534# elif defined RT_OS_WINDOWS
535# ifndef VBOX_WITH_NETFLT
536 hr = E_NOTIMPL;
537# else /* # if defined VBOX_WITH_NETFLT */
538 INetCfg *pNc;
539 INetCfgComponent *pMpNcc;
540 INetCfgComponent *pTcpIpNcc;
541 LPWSTR lpszApp;
542 HRESULT hr;
543 IEnumNetCfgBindingPath *pEnumBp;
544 INetCfgBindingPath *pBp;
545 IEnumNetCfgBindingInterface *pEnumBi;
546 INetCfgBindingInterface *pBi;
547
548 /* we are using the INetCfg API for getting the list of miniports */
549 hr = VBoxNetCfgWinQueryINetCfg( FALSE,
550 VBOX_APP_NAME,
551 &pNc,
552 &lpszApp );
553 Assert(hr == S_OK);
554 if (hr == S_OK)
555 {
556# ifdef VBOX_NETFLT_ONDEMAND_BIND
557 /* for the protocol-based approach for now we just get all miniports the MS_TCPIP protocol binds to */
558 hr = pNc->FindComponent(L"MS_TCPIP", &pTcpIpNcc);
559# else
560 /* for the filter-based approach we get all miniports our filter (sun_VBoxNetFlt)is bound to */
561 hr = pNc->FindComponent(L"sun_VBoxNetFlt", &pTcpIpNcc);
562# ifndef VBOX_WITH_HARDENING
563 if (hr != S_OK)
564 {
565 /* TODO: try to install the netflt from here */
566 }
567# endif
568
569# endif
570
571 if (hr == S_OK)
572 {
573 hr = VBoxNetCfgWinGetBindingPathEnum(pTcpIpNcc, EBP_BELOW, &pEnumBp);
574 Assert(hr == S_OK);
575 if ( hr == S_OK )
576 {
577 hr = VBoxNetCfgWinGetFirstBindingPath(pEnumBp, &pBp);
578 Assert(hr == S_OK || hr == S_FALSE);
579 while( hr == S_OK )
580 {
581 /* S_OK == enabled, S_FALSE == disabled */
582 if (pBp->IsEnabled() == S_OK)
583 {
584 hr = VBoxNetCfgWinGetBindingInterfaceEnum(pBp, &pEnumBi);
585 Assert(hr == S_OK);
586 if ( hr == S_OK )
587 {
588 hr = VBoxNetCfgWinGetFirstBindingInterface(pEnumBi, &pBi);
589 Assert(hr == S_OK);
590 while(hr == S_OK)
591 {
592 hr = pBi->GetLowerComponent( &pMpNcc );
593 Assert(hr == S_OK);
594 if (hr == S_OK)
595 {
596 ULONG uComponentStatus;
597 hr = pMpNcc->GetDeviceStatus(&uComponentStatus);
598 Assert(hr == S_OK);
599 if (hr == S_OK)
600 {
601 if (uComponentStatus == 0)
602 {
603 vboxNetWinAddComponent(&list, pMpNcc);
604 }
605 }
606 VBoxNetCfgWinReleaseRef( pMpNcc );
607 }
608 VBoxNetCfgWinReleaseRef(pBi);
609
610 hr = VBoxNetCfgWinGetNextBindingInterface(pEnumBi, &pBi);
611 }
612 VBoxNetCfgWinReleaseRef(pEnumBi);
613 }
614 }
615 VBoxNetCfgWinReleaseRef(pBp);
616
617 hr = VBoxNetCfgWinGetNextBindingPath(pEnumBp, &pBp);
618 }
619 VBoxNetCfgWinReleaseRef(pEnumBp);
620 }
621 VBoxNetCfgWinReleaseRef(pTcpIpNcc);
622 }
623 else
624 {
625 LogRel(("failed to get the sun_VBoxNetFlt component, error (0x%x)", hr));
626 }
627
628 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE);
629 }
630# endif /* # if defined VBOX_WITH_NETFLT */
631
632
633# elif defined RT_OS_LINUX
634 int sock = socket(AF_INET, SOCK_DGRAM, 0);
635 if (sock >= 0)
636 {
637 char pBuffer[2048];
638 struct ifconf ifConf;
639 ifConf.ifc_len = sizeof(pBuffer);
640 ifConf.ifc_buf = pBuffer;
641 if (ioctl(sock, SIOCGIFCONF, &ifConf) >= 0)
642 {
643 for (struct ifreq *pReq = ifConf.ifc_req; (char*)pReq < pBuffer + ifConf.ifc_len; pReq++)
644 {
645 if (ioctl(sock, SIOCGIFHWADDR, pReq) >= 0)
646 {
647 if (pReq->ifr_hwaddr.sa_family == ARPHRD_ETHER)
648 {
649 RTUUID uuid;
650 Assert(sizeof(uuid) <= sizeof(*pReq));
651 memcpy(&uuid, pReq, sizeof(uuid));
652
653 ComObjPtr<HostNetworkInterface> IfObj;
654 IfObj.createObject();
655 if (SUCCEEDED(IfObj->init(Bstr(pReq->ifr_name), Guid(uuid), HostNetworkInterfaceType_Bridged)))
656 list.push_back(IfObj);
657 }
658 }
659 }
660 }
661 close(sock);
662 }
663# endif /* RT_OS_LINUX */
664# endif
665
666 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
667 for (it = list.begin(); it != list.end(); ++it)
668 {
669 (*it)->setVirtualBox(m->pParent);
670 }
671
672 SafeIfaceArray<IHostNetworkInterface> networkInterfaces (list);
673 networkInterfaces.detachTo(ComSafeArrayOutArg(aNetworkInterfaces));
674
675 return S_OK;
676
677#else
678 /* Not implemented / supported on this platform. */
679 ReturnComNotImplemented();
680#endif
681}
682
683STDMETHODIMP Host::COMGETTER(USBDevices)(ComSafeArrayOut(IHostUSBDevice*, aUSBDevices))
684{
685#ifdef VBOX_WITH_USB
686 CheckComArgOutSafeArrayPointerValid(aUSBDevices);
687
688 AutoCaller autoCaller(this);
689 if (FAILED(autoCaller.rc())) return autoCaller.rc();
690
691 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
692
693 MultiResult rc = checkUSBProxyService();
694 if (FAILED(rc)) return rc;
695
696 return m->pUSBProxyService->getDeviceCollection(ComSafeArrayOutArg(aUSBDevices));
697
698#else
699 /* Note: The GUI depends on this method returning E_NOTIMPL with no
700 * extended error info to indicate that USB is simply not available
701 * (w/o treating it as a failure), for example, as in OSE. */
702 NOREF(aUSBDevices);
703# ifndef RT_OS_WINDOWS
704 NOREF(aUSBDevicesSize);
705# endif
706 ReturnComNotImplemented();
707#endif
708}
709
710STDMETHODIMP Host::COMGETTER(USBDeviceFilters)(ComSafeArrayOut(IHostUSBDeviceFilter*, aUSBDeviceFilters))
711{
712#ifdef VBOX_WITH_USB
713 CheckComArgOutSafeArrayPointerValid(aUSBDeviceFilters);
714
715 AutoCaller autoCaller(this);
716 if (FAILED(autoCaller.rc())) return autoCaller.rc();
717
718 AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
719
720 MultiResult rc = checkUSBProxyService();
721 if (FAILED(rc)) return rc;
722
723 SafeIfaceArray<IHostUSBDeviceFilter> collection(m->llUSBDeviceFilters);
724 collection.detachTo(ComSafeArrayOutArg(aUSBDeviceFilters));
725
726 return rc;
727#else
728 /* Note: The GUI depends on this method returning E_NOTIMPL with no
729 * extended error info to indicate that USB is simply not available
730 * (w/o treating it as a failure), for example, as in OSE. */
731 NOREF(aUSBDeviceFilters);
732# ifndef RT_OS_WINDOWS
733 NOREF(aUSBDeviceFiltersSize);
734# endif
735 ReturnComNotImplemented();
736#endif
737}
738
739/**
740 * Returns the number of installed logical processors
741 *
742 * @returns COM status code
743 * @param count address of result variable
744 */
745STDMETHODIMP Host::COMGETTER(ProcessorCount)(ULONG *aCount)
746{
747 CheckComArgOutPointerValid(aCount);
748 // no locking required
749
750 *aCount = RTMpGetPresentCount();
751 return S_OK;
752}
753
754/**
755 * Returns the number of online logical processors
756 *
757 * @returns COM status code
758 * @param count address of result variable
759 */
760STDMETHODIMP Host::COMGETTER(ProcessorOnlineCount)(ULONG *aCount)
761{
762 CheckComArgOutPointerValid(aCount);
763 // no locking required
764
765 *aCount = RTMpGetOnlineCount();
766 return S_OK;
767}
768
769/**
770 * Returns the (approximate) maximum speed of the given host CPU in MHz
771 *
772 * @returns COM status code
773 * @param cpu id to get info for.
774 * @param speed address of result variable, speed is 0 if unknown or aCpuId is invalid.
775 */
776STDMETHODIMP Host::GetProcessorSpeed(ULONG aCpuId, ULONG *aSpeed)
777{
778 CheckComArgOutPointerValid(aSpeed);
779 // no locking required
780
781 *aSpeed = RTMpGetMaxFrequency(aCpuId);
782 return S_OK;
783}
784
785/**
786 * Returns a description string for the host CPU
787 *
788 * @returns COM status code
789 * @param cpu id to get info for.
790 * @param description address of result variable, empty string if not known or aCpuId is invalid.
791 */
792STDMETHODIMP Host::GetProcessorDescription(ULONG aCpuId, BSTR *aDescription)
793{
794 CheckComArgOutPointerValid(aDescription);
795 // no locking required
796
797 char szCPUModel[80];
798 int vrc = RTMpGetDescription(aCpuId, szCPUModel, sizeof(szCPUModel));
799 if (RT_FAILURE(vrc))
800 return E_FAIL; /** @todo error reporting? */
801 Bstr (szCPUModel).cloneTo(aDescription);
802 return S_OK;
803}
804
805/**
806 * Returns whether a host processor feature is supported or not
807 *
808 * @returns COM status code
809 * @param Feature to query.
810 * @param address of supported bool result variable
811 */
812STDMETHODIMP Host::GetProcessorFeature(ProcessorFeature_T aFeature, BOOL *aSupported)
813{
814 CheckComArgOutPointerValid(aSupported);
815 AutoCaller autoCaller(this);
816 if (FAILED(autoCaller.rc())) return autoCaller.rc();
817
818 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
819
820 switch (aFeature)
821 {
822 case ProcessorFeature_HWVirtEx:
823 *aSupported = m->fVTSupported;
824 break;
825
826 case ProcessorFeature_PAE:
827 *aSupported = m->fPAESupported;
828 break;
829
830 case ProcessorFeature_LongMode:
831 *aSupported = m->fLongModeSupported;
832 break;
833
834 case ProcessorFeature_NestedPaging:
835 *aSupported = m->fNestedPagingSupported;
836 break;
837
838 default:
839 ReturnComNotImplemented();
840 }
841 return S_OK;
842}
843
844/**
845 * Returns the specific CPUID leaf.
846 *
847 * @returns COM status code
848 * @param aCpuId The CPU number. Mostly ignored.
849 * @param aLeaf The leaf number.
850 * @param aSubLeaf The sub-leaf number.
851 * @param aValEAX Where to return EAX.
852 * @param aValEBX Where to return EBX.
853 * @param aValECX Where to return ECX.
854 * @param aValEDX Where to return EDX.
855 */
856STDMETHODIMP Host::GetProcessorCPUIDLeaf(ULONG aCpuId, ULONG aLeaf, ULONG aSubLeaf,
857 ULONG *aValEAX, ULONG *aValEBX, ULONG *aValECX, ULONG *aValEDX)
858{
859 CheckComArgOutPointerValid(aValEAX);
860 CheckComArgOutPointerValid(aValEBX);
861 CheckComArgOutPointerValid(aValECX);
862 CheckComArgOutPointerValid(aValEDX);
863 // no locking required
864
865 /* Check that the CPU is online. */
866 /** @todo later use RTMpOnSpecific. */
867 if (!RTMpIsCpuOnline(aCpuId))
868 return RTMpIsCpuPresent(aCpuId)
869 ? setError(E_FAIL, tr("CPU no.%u is not present"), aCpuId)
870 : setError(E_FAIL, tr("CPU no.%u is not online"), aCpuId);
871
872 uint32_t uEAX, uEBX, uECX, uEDX;
873 ASMCpuId_Idx_ECX(aLeaf, aSubLeaf, &uEAX, &uEBX, &uECX, &uEDX);
874 *aValEAX = uEAX;
875 *aValEBX = uEBX;
876 *aValECX = uECX;
877 *aValEDX = uEDX;
878
879 return S_OK;
880}
881
882/**
883 * Returns the amount of installed system memory in megabytes
884 *
885 * @returns COM status code
886 * @param size address of result variable
887 */
888STDMETHODIMP Host::COMGETTER(MemorySize)(ULONG *aSize)
889{
890 CheckComArgOutPointerValid(aSize);
891 // no locking required
892
893 /* @todo This is an ugly hack. There must be a function in IPRT for that. */
894 pm::CollectorHAL *hal = pm::createHAL();
895 if (!hal)
896 return E_FAIL;
897 ULONG tmp;
898 int rc = hal->getHostMemoryUsage(aSize, &tmp, &tmp);
899 *aSize /= 1024;
900 delete hal;
901 return rc;
902}
903
904/**
905 * Returns the current system memory free space in megabytes
906 *
907 * @returns COM status code
908 * @param available address of result variable
909 */
910STDMETHODIMP Host::COMGETTER(MemoryAvailable)(ULONG *aAvailable)
911{
912 CheckComArgOutPointerValid(aAvailable);
913 // no locking required
914
915 /* @todo This is an ugly hack. There must be a function in IPRT for that. */
916 pm::CollectorHAL *hal = pm::createHAL();
917 if (!hal)
918 return E_FAIL;
919 ULONG tmp;
920 int rc = hal->getHostMemoryUsage(&tmp, &tmp, aAvailable);
921 *aAvailable /= 1024;
922 delete hal;
923 return rc;
924}
925
926/**
927 * Returns the name string of the host operating system
928 *
929 * @returns COM status code
930 * @param os address of result variable
931 */
932STDMETHODIMP Host::COMGETTER(OperatingSystem)(BSTR *aOs)
933{
934 CheckComArgOutPointerValid(aOs);
935 // no locking required
936
937 char szOSName[80];
938 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szOSName, sizeof(szOSName));
939 if (RT_FAILURE(vrc))
940 return E_FAIL; /** @todo error reporting? */
941 Bstr (szOSName).cloneTo(aOs);
942 return S_OK;
943}
944
945/**
946 * Returns the version string of the host operating system
947 *
948 * @returns COM status code
949 * @param os address of result variable
950 */
951STDMETHODIMP Host::COMGETTER(OSVersion)(BSTR *aVersion)
952{
953 CheckComArgOutPointerValid(aVersion);
954 // no locking required
955
956 /* Get the OS release. Reserve some buffer space for the service pack. */
957 char szOSRelease[128];
958 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOSRelease, sizeof(szOSRelease) - 32);
959 if (RT_FAILURE(vrc))
960 return E_FAIL; /** @todo error reporting? */
961
962 /* Append the service pack if present. */
963 char szOSServicePack[80];
964 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szOSServicePack, sizeof(szOSServicePack));
965 if (RT_FAILURE(vrc))
966 {
967 if (vrc != VERR_NOT_SUPPORTED)
968 return E_FAIL; /** @todo error reporting? */
969 szOSServicePack[0] = '\0';
970 }
971 if (szOSServicePack[0] != '\0')
972 {
973 char *psz = strchr(szOSRelease, '\0');
974 RTStrPrintf(psz, &szOSRelease[sizeof(szOSRelease)] - psz, "sp%s", szOSServicePack);
975 }
976
977 Bstr(szOSRelease).cloneTo(aVersion);
978 return S_OK;
979}
980
981/**
982 * Returns the current host time in milliseconds since 1970-01-01 UTC.
983 *
984 * @returns COM status code
985 * @param time address of result variable
986 */
987STDMETHODIMP Host::COMGETTER(UTCTime)(LONG64 *aUTCTime)
988{
989 CheckComArgOutPointerValid(aUTCTime);
990 // no locking required
991
992 RTTIMESPEC now;
993 *aUTCTime = RTTimeSpecGetMilli(RTTimeNow(&now));
994
995 return S_OK;
996}
997
998STDMETHODIMP Host::COMGETTER(Acceleration3DAvailable)(BOOL *aSupported)
999{
1000 CheckComArgOutPointerValid(aSupported);
1001 AutoCaller autoCaller(this);
1002 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1003
1004 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1005
1006 *aSupported = m->f3DAccelerationSupported;
1007
1008 return S_OK;
1009}
1010
1011STDMETHODIMP Host::CreateHostOnlyNetworkInterface(IHostNetworkInterface **aHostNetworkInterface,
1012 IProgress **aProgress)
1013{
1014 CheckComArgOutPointerValid(aHostNetworkInterface);
1015 CheckComArgOutPointerValid(aProgress);
1016
1017 AutoCaller autoCaller(this);
1018 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1019
1020 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1021
1022 int r = NetIfCreateHostOnlyNetworkInterface(m->pParent, aHostNetworkInterface, aProgress);
1023 if (RT_SUCCESS(r))
1024 return S_OK;
1025
1026 return r == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
1027}
1028
1029STDMETHODIMP Host::RemoveHostOnlyNetworkInterface(IN_BSTR aId,
1030 IProgress **aProgress)
1031{
1032 CheckComArgOutPointerValid(aProgress);
1033
1034 AutoCaller autoCaller(this);
1035 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1036
1037 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1038
1039 /* first check whether an interface with the given name already exists */
1040 {
1041 ComPtr<IHostNetworkInterface> iface;
1042 if (FAILED(FindHostNetworkInterfaceById(aId,
1043 iface.asOutParam())))
1044 return setError(VBOX_E_OBJECT_NOT_FOUND,
1045 tr("Host network interface with UUID {%RTuuid} does not exist"),
1046 Guid (aId).raw());
1047 }
1048
1049 int r = NetIfRemoveHostOnlyNetworkInterface(m->pParent, Guid(aId), aProgress);
1050 if (RT_SUCCESS(r))
1051 return S_OK;
1052
1053 return r == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
1054}
1055
1056STDMETHODIMP Host::CreateUSBDeviceFilter(IN_BSTR aName,
1057 IHostUSBDeviceFilter **aFilter)
1058{
1059#ifdef VBOX_WITH_USB
1060 CheckComArgStrNotEmptyOrNull(aName);
1061 CheckComArgOutPointerValid(aFilter);
1062
1063 AutoCaller autoCaller(this);
1064 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1065
1066 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1067
1068 ComObjPtr<HostUSBDeviceFilter> filter;
1069 filter.createObject();
1070 HRESULT rc = filter->init(this, aName);
1071 ComAssertComRCRet(rc, rc);
1072 rc = filter.queryInterfaceTo(aFilter);
1073 AssertComRCReturn(rc, rc);
1074 return S_OK;
1075#else
1076 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1077 * extended error info to indicate that USB is simply not available
1078 * (w/o treating it as a failure), for example, as in OSE. */
1079 NOREF(aName);
1080 NOREF(aFilter);
1081 ReturnComNotImplemented();
1082#endif
1083}
1084
1085STDMETHODIMP Host::InsertUSBDeviceFilter(ULONG aPosition,
1086 IHostUSBDeviceFilter *aFilter)
1087{
1088#ifdef VBOX_WITH_USB
1089 CheckComArgNotNull(aFilter);
1090
1091 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1092 AutoCaller autoCaller(this);
1093 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1094
1095 AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1096
1097 MultiResult rc = checkUSBProxyService();
1098 if (FAILED(rc)) return rc;
1099
1100 ComObjPtr<HostUSBDeviceFilter> pFilter;
1101 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
1102 it != m->llChildren.end();
1103 ++it)
1104 {
1105 if (*it == aFilter)
1106 {
1107 pFilter = *it;
1108 break;
1109 }
1110 }
1111 if (pFilter.isNull())
1112 return setError(VBOX_E_INVALID_OBJECT_STATE,
1113 tr("The given USB device filter is not created within this VirtualBox instance"));
1114
1115 if (pFilter->mInList)
1116 return setError(E_INVALIDARG,
1117 tr("The given USB device filter is already in the list"));
1118
1119 /* iterate to the position... */
1120 USBDeviceFilterList::iterator itPos = m->llUSBDeviceFilters.begin();
1121 std::advance(itPos, aPosition);
1122 /* ...and insert */
1123 m->llUSBDeviceFilters.insert(itPos, pFilter);
1124 pFilter->mInList = true;
1125
1126 /* notify the proxy (only when the filter is active) */
1127 if ( m->pUSBProxyService->isActive()
1128 && pFilter->getData().mActive)
1129 {
1130 ComAssertRet(pFilter->getId() == NULL, E_FAIL);
1131 pFilter->getId() = m->pUSBProxyService->insertFilter(&pFilter->getData().mUSBFilter);
1132 }
1133
1134 /* save the global settings */
1135 alock.release();
1136 return rc = m->pParent->saveSettings();
1137#else
1138 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1139 * extended error info to indicate that USB is simply not available
1140 * (w/o treating it as a failure), for example, as in OSE. */
1141 NOREF(aPosition);
1142 NOREF(aFilter);
1143 ReturnComNotImplemented();
1144#endif
1145}
1146
1147STDMETHODIMP Host::RemoveUSBDeviceFilter(ULONG aPosition)
1148{
1149#ifdef VBOX_WITH_USB
1150
1151 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1152 AutoCaller autoCaller(this);
1153 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1154
1155 AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1156
1157 MultiResult rc = checkUSBProxyService();
1158 if (FAILED(rc)) return rc;
1159
1160 if (!m->llUSBDeviceFilters.size())
1161 return setError(E_INVALIDARG,
1162 tr("The USB device filter list is empty"));
1163
1164 if (aPosition >= m->llUSBDeviceFilters.size())
1165 return setError(E_INVALIDARG,
1166 tr("Invalid position: %lu (must be in range [0, %lu])"),
1167 aPosition, m->llUSBDeviceFilters.size() - 1);
1168
1169 ComObjPtr<HostUSBDeviceFilter> filter;
1170 {
1171 /* iterate to the position... */
1172 USBDeviceFilterList::iterator it = m->llUSBDeviceFilters.begin();
1173 std::advance (it, aPosition);
1174 /* ...get an element from there... */
1175 filter = *it;
1176 /* ...and remove */
1177 filter->mInList = false;
1178 m->llUSBDeviceFilters.erase(it);
1179 }
1180
1181 /* notify the proxy (only when the filter is active) */
1182 if (m->pUSBProxyService->isActive() && filter->getData().mActive)
1183 {
1184 ComAssertRet(filter->getId() != NULL, E_FAIL);
1185 m->pUSBProxyService->removeFilter(filter->getId());
1186 filter->getId() = NULL;
1187 }
1188
1189 /* save the global settings */
1190 alock.release();
1191 return rc = m->pParent->saveSettings();
1192#else
1193 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1194 * extended error info to indicate that USB is simply not available
1195 * (w/o treating it as a failure), for example, as in OSE. */
1196 NOREF(aPosition);
1197 ReturnComNotImplemented();
1198#endif
1199}
1200
1201STDMETHODIMP Host::FindHostDVDDrive(IN_BSTR aName, IMedium **aDrive)
1202{
1203 CheckComArgStrNotEmptyOrNull(aName);
1204 CheckComArgOutPointerValid(aDrive);
1205
1206 *aDrive = NULL;
1207
1208 SafeIfaceArray<IMedium> drivevec;
1209 HRESULT rc = COMGETTER(DVDDrives)(ComSafeArrayAsOutParam(drivevec));
1210 if (FAILED(rc)) return rc;
1211
1212 for (size_t i = 0; i < drivevec.size(); ++i)
1213 {
1214 ComPtr<IMedium> drive = drivevec[i];
1215 Bstr name, location;
1216 rc = drive->COMGETTER(Name)(name.asOutParam());
1217 if (FAILED(rc)) return rc;
1218 rc = drive->COMGETTER(Location)(location.asOutParam());
1219 if (FAILED(rc)) return rc;
1220 if (name == aName || location == aName)
1221 return drive.queryInterfaceTo(aDrive);
1222 }
1223
1224 return setError(VBOX_E_OBJECT_NOT_FOUND,
1225 Medium::tr("The host DVD drive named '%ls' could not be found"), aName);
1226}
1227
1228STDMETHODIMP Host::FindHostFloppyDrive(IN_BSTR aName, IMedium **aDrive)
1229{
1230 CheckComArgStrNotEmptyOrNull(aName);
1231 CheckComArgOutPointerValid(aDrive);
1232
1233 *aDrive = NULL;
1234
1235 SafeIfaceArray<IMedium> drivevec;
1236 HRESULT rc = COMGETTER(FloppyDrives)(ComSafeArrayAsOutParam(drivevec));
1237 if (FAILED(rc)) return rc;
1238
1239 for (size_t i = 0; i < drivevec.size(); ++i)
1240 {
1241 ComPtr<IMedium> drive = drivevec[i];
1242 Bstr name;
1243 rc = drive->COMGETTER(Name)(name.asOutParam());
1244 if (FAILED(rc)) return rc;
1245 if (name == aName)
1246 return drive.queryInterfaceTo(aDrive);
1247 }
1248
1249 return setError(VBOX_E_OBJECT_NOT_FOUND,
1250 Medium::tr("The host floppy drive named '%ls' could not be found"), aName);
1251}
1252
1253STDMETHODIMP Host::FindHostNetworkInterfaceByName(IN_BSTR name, IHostNetworkInterface **networkInterface)
1254{
1255#ifndef VBOX_WITH_HOSTNETIF_API
1256 return E_NOTIMPL;
1257#else
1258 if (!name)
1259 return E_INVALIDARG;
1260 if (!networkInterface)
1261 return E_POINTER;
1262
1263 *networkInterface = NULL;
1264 ComObjPtr<HostNetworkInterface> found;
1265 std::list <ComObjPtr<HostNetworkInterface> > list;
1266 int rc = NetIfList(list);
1267 if (RT_FAILURE(rc))
1268 {
1269 Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
1270 return E_FAIL;
1271 }
1272 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
1273 for (it = list.begin(); it != list.end(); ++it)
1274 {
1275 Bstr n;
1276 (*it)->COMGETTER(Name) (n.asOutParam());
1277 if (n == name)
1278 found = *it;
1279 }
1280
1281 if (!found)
1282 return setError(E_INVALIDARG,
1283 HostNetworkInterface::tr("The host network interface with the given name could not be found"));
1284
1285 found->setVirtualBox(m->pParent);
1286
1287 return found.queryInterfaceTo(networkInterface);
1288#endif
1289}
1290
1291STDMETHODIMP Host::FindHostNetworkInterfaceById(IN_BSTR id, IHostNetworkInterface **networkInterface)
1292{
1293#ifndef VBOX_WITH_HOSTNETIF_API
1294 return E_NOTIMPL;
1295#else
1296 if (Guid(id).isEmpty())
1297 return E_INVALIDARG;
1298 if (!networkInterface)
1299 return E_POINTER;
1300
1301 *networkInterface = NULL;
1302 ComObjPtr<HostNetworkInterface> found;
1303 std::list <ComObjPtr<HostNetworkInterface> > list;
1304 int rc = NetIfList(list);
1305 if (RT_FAILURE(rc))
1306 {
1307 Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
1308 return E_FAIL;
1309 }
1310 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
1311 for (it = list.begin(); it != list.end(); ++it)
1312 {
1313 Bstr g;
1314 (*it)->COMGETTER(Id) (g.asOutParam());
1315 if (g == id)
1316 found = *it;
1317 }
1318
1319 if (!found)
1320 return setError(E_INVALIDARG,
1321 HostNetworkInterface::tr("The host network interface with the given GUID could not be found"));
1322
1323 found->setVirtualBox(m->pParent);
1324
1325 return found.queryInterfaceTo(networkInterface);
1326#endif
1327}
1328
1329STDMETHODIMP Host::FindHostNetworkInterfacesOfType(HostNetworkInterfaceType_T type,
1330 ComSafeArrayOut(IHostNetworkInterface *, aNetworkInterfaces))
1331{
1332 std::list <ComObjPtr<HostNetworkInterface> > allList;
1333 int rc = NetIfList(allList);
1334 if (RT_FAILURE(rc))
1335 return E_FAIL;
1336
1337 std::list <ComObjPtr<HostNetworkInterface> > resultList;
1338
1339 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
1340 for (it = allList.begin(); it != allList.end(); ++it)
1341 {
1342 HostNetworkInterfaceType_T t;
1343 HRESULT hr = (*it)->COMGETTER(InterfaceType)(&t);
1344 if (FAILED(hr))
1345 return hr;
1346
1347 if (t == type)
1348 {
1349 (*it)->setVirtualBox(m->pParent);
1350 resultList.push_back (*it);
1351 }
1352 }
1353
1354 SafeIfaceArray<IHostNetworkInterface> filteredNetworkInterfaces (resultList);
1355 filteredNetworkInterfaces.detachTo(ComSafeArrayOutArg(aNetworkInterfaces));
1356
1357 return S_OK;
1358}
1359
1360STDMETHODIMP Host::FindUSBDeviceByAddress(IN_BSTR aAddress,
1361 IHostUSBDevice **aDevice)
1362{
1363#ifdef VBOX_WITH_USB
1364 CheckComArgStrNotEmptyOrNull(aAddress);
1365 CheckComArgOutPointerValid(aDevice);
1366
1367 *aDevice = NULL;
1368
1369 SafeIfaceArray<IHostUSBDevice> devsvec;
1370 HRESULT rc = COMGETTER(USBDevices) (ComSafeArrayAsOutParam(devsvec));
1371 if (FAILED(rc)) return rc;
1372
1373 for (size_t i = 0; i < devsvec.size(); ++i)
1374 {
1375 Bstr address;
1376 rc = devsvec[i]->COMGETTER(Address) (address.asOutParam());
1377 if (FAILED(rc)) return rc;
1378 if (address == aAddress)
1379 {
1380 return ComObjPtr<IHostUSBDevice> (devsvec[i]).queryInterfaceTo(aDevice);
1381 }
1382 }
1383
1384 return setErrorNoLog (VBOX_E_OBJECT_NOT_FOUND, tr (
1385 "Could not find a USB device with address '%ls'"),
1386 aAddress);
1387
1388#else /* !VBOX_WITH_USB */
1389 NOREF(aAddress);
1390 NOREF(aDevice);
1391 return E_NOTIMPL;
1392#endif /* !VBOX_WITH_USB */
1393}
1394
1395STDMETHODIMP Host::FindUSBDeviceById(IN_BSTR aId,
1396 IHostUSBDevice **aDevice)
1397{
1398#ifdef VBOX_WITH_USB
1399 CheckComArgExpr(aId, Guid (aId).isEmpty() == false);
1400 CheckComArgOutPointerValid(aDevice);
1401
1402 *aDevice = NULL;
1403
1404 SafeIfaceArray<IHostUSBDevice> devsvec;
1405 HRESULT rc = COMGETTER(USBDevices) (ComSafeArrayAsOutParam(devsvec));
1406 if (FAILED(rc)) return rc;
1407
1408 for (size_t i = 0; i < devsvec.size(); ++i)
1409 {
1410 Bstr id;
1411 rc = devsvec[i]->COMGETTER(Id) (id.asOutParam());
1412 if (FAILED(rc)) return rc;
1413 if (id == aId)
1414 {
1415 return ComObjPtr<IHostUSBDevice> (devsvec[i]).queryInterfaceTo(aDevice);
1416 }
1417 }
1418
1419 return setErrorNoLog (VBOX_E_OBJECT_NOT_FOUND, tr (
1420 "Could not find a USB device with uuid {%RTuuid}"),
1421 Guid (aId).raw());
1422
1423#else /* !VBOX_WITH_USB */
1424 NOREF(aId);
1425 NOREF(aDevice);
1426 return E_NOTIMPL;
1427#endif /* !VBOX_WITH_USB */
1428}
1429
1430// public methods only for internal purposes
1431////////////////////////////////////////////////////////////////////////////////
1432
1433HRESULT Host::loadSettings(const settings::Host &data)
1434{
1435 HRESULT rc = S_OK;
1436#ifdef VBOX_WITH_USB
1437 AutoCaller autoCaller(this);
1438 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1439
1440 AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1441
1442
1443 for (settings::USBDeviceFiltersList::const_iterator it = data.llUSBDeviceFilters.begin();
1444 it != data.llUSBDeviceFilters.end();
1445 ++it)
1446 {
1447 const settings::USBDeviceFilter &f = *it;
1448 ComObjPtr<HostUSBDeviceFilter> pFilter;
1449 pFilter.createObject();
1450 rc = pFilter->init(this, f);
1451 if (FAILED(rc)) break;
1452
1453 m->llUSBDeviceFilters.push_back(pFilter);
1454 pFilter->mInList = true;
1455
1456 /* notify the proxy (only when the filter is active) */
1457 if (pFilter->getData().mActive)
1458 {
1459 HostUSBDeviceFilter *flt = pFilter; /* resolve ambiguity */
1460 flt->getId() = m->pUSBProxyService->insertFilter(&pFilter->getData().mUSBFilter);
1461 }
1462 }
1463#else
1464 NOREF(data);
1465#endif /* VBOX_WITH_USB */
1466 return rc;
1467}
1468
1469HRESULT Host::saveSettings(settings::Host &data)
1470{
1471#ifdef VBOX_WITH_USB
1472 AutoCaller autoCaller(this);
1473 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1474
1475 AutoReadLock alock(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1476
1477 data.llUSBDeviceFilters.clear();
1478
1479 for (USBDeviceFilterList::const_iterator it = m->llUSBDeviceFilters.begin();
1480 it != m->llUSBDeviceFilters.end();
1481 ++it)
1482 {
1483 ComObjPtr<HostUSBDeviceFilter> pFilter = *it;
1484 settings::USBDeviceFilter f;
1485 pFilter->saveSettings(f);
1486 data.llUSBDeviceFilters.push_back(f);
1487 }
1488#else
1489 NOREF(data);
1490#endif /* VBOX_WITH_USB */
1491
1492 return S_OK;
1493}
1494
1495HRESULT Host::getDVDDrives(MediaList &list)
1496{
1497 HRESULT rc = S_OK;
1498
1499 Assert(isWriteLockOnCurrentThread());
1500
1501 try
1502 {
1503#if defined(RT_OS_WINDOWS)
1504 int sz = GetLogicalDriveStrings(0, NULL);
1505 TCHAR *hostDrives = new TCHAR[sz+1];
1506 GetLogicalDriveStrings(sz, hostDrives);
1507 wchar_t driveName[3] = { '?', ':', '\0' };
1508 TCHAR *p = hostDrives;
1509 do
1510 {
1511 if (GetDriveType(p) == DRIVE_CDROM)
1512 {
1513 driveName[0] = *p;
1514 ComObjPtr<Medium> hostDVDDriveObj;
1515 hostDVDDriveObj.createObject();
1516 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(driveName));
1517 list.push_back(hostDVDDriveObj);
1518 }
1519 p += _tcslen(p) + 1;
1520 }
1521 while (*p);
1522 delete[] hostDrives;
1523
1524#elif defined(RT_OS_SOLARIS)
1525# ifdef VBOX_USE_LIBHAL
1526 if (!getDVDInfoFromHal(list))
1527# endif
1528 // Not all Solaris versions ship with libhal.
1529 // So use a fallback approach similar to Linux.
1530 {
1531 if (RTEnvExistEx(RTENV_DEFAULT, "VBOX_CDROM"))
1532 {
1533 char *cdromEnv = RTEnvDupEx(RTENV_DEFAULT, "VBOX_CDROM");
1534 char *saveStr = NULL;
1535 char *cdromDrive = NULL;
1536 if (cdromEnv)
1537 cdromDrive = strtok_r(cdromEnv, ":", &saveStr);
1538 while (cdromDrive)
1539 {
1540 if (validateDevice(cdromDrive, true))
1541 {
1542 ComObjPtr<Medium> hostDVDDriveObj;
1543 hostDVDDriveObj.createObject();
1544 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(cdromDrive));
1545 list.push_back(hostDVDDriveObj);
1546 }
1547 cdromDrive = strtok_r(NULL, ":", &saveStr);
1548 }
1549 RTStrFree(cdromEnv);
1550 }
1551 else
1552 {
1553 // this might work on Solaris version older than Nevada.
1554 if (validateDevice("/cdrom/cdrom0", true))
1555 {
1556 ComObjPtr<Medium> hostDVDDriveObj;
1557 hostDVDDriveObj.createObject();
1558 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr("cdrom/cdrom0"));
1559 list.push_back(hostDVDDriveObj);
1560 }
1561
1562 // check the mounted drives
1563 parseMountTable(MNTTAB, list);
1564 }
1565 }
1566
1567#elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
1568 if (RT_SUCCESS(m->hostDrives.updateDVDs()))
1569 for (DriveInfoList::const_iterator it = m->hostDrives.DVDBegin();
1570 SUCCEEDED(rc) && it != m->hostDrives.DVDEnd(); ++it)
1571 {
1572 ComObjPtr<Medium> hostDVDDriveObj;
1573 Bstr location(it->mDevice);
1574 Bstr description(it->mDescription);
1575 if (SUCCEEDED(rc))
1576 rc = hostDVDDriveObj.createObject();
1577 if (SUCCEEDED(rc))
1578 rc = hostDVDDriveObj->init(m->pParent, DeviceType_DVD, location, description);
1579 if (SUCCEEDED(rc))
1580 list.push_back(hostDVDDriveObj);
1581 }
1582#elif defined(RT_OS_DARWIN)
1583 PDARWINDVD cur = DarwinGetDVDDrives();
1584 while (cur)
1585 {
1586 ComObjPtr<Medium> hostDVDDriveObj;
1587 hostDVDDriveObj.createObject();
1588 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(cur->szName));
1589 list.push_back(hostDVDDriveObj);
1590
1591 /* next */
1592 void *freeMe = cur;
1593 cur = cur->pNext;
1594 RTMemFree(freeMe);
1595 }
1596#else
1597 /* PORTME */
1598#endif
1599 }
1600 catch(std::bad_alloc &)
1601 {
1602 rc = E_OUTOFMEMORY;
1603 }
1604 return rc;
1605}
1606
1607/**
1608 * Internal implementation for COMGETTER(FloppyDrives) which can be called
1609 * from elsewhere. Caller must hold the Host object write lock!
1610 * @param list
1611 * @return
1612 */
1613HRESULT Host::getFloppyDrives(MediaList &list)
1614{
1615 HRESULT rc = S_OK;
1616
1617 Assert(isWriteLockOnCurrentThread());
1618
1619 try
1620 {
1621#ifdef RT_OS_WINDOWS
1622 int sz = GetLogicalDriveStrings(0, NULL);
1623 TCHAR *hostDrives = new TCHAR[sz+1];
1624 GetLogicalDriveStrings(sz, hostDrives);
1625 wchar_t driveName[3] = { '?', ':', '\0' };
1626 TCHAR *p = hostDrives;
1627 do
1628 {
1629 if (GetDriveType(p) == DRIVE_REMOVABLE)
1630 {
1631 driveName[0] = *p;
1632 ComObjPtr<Medium> hostFloppyDriveObj;
1633 hostFloppyDriveObj.createObject();
1634 hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, Bstr(driveName));
1635 list.push_back(hostFloppyDriveObj);
1636 }
1637 p += _tcslen(p) + 1;
1638 }
1639 while (*p);
1640 delete[] hostDrives;
1641#elif defined(RT_OS_LINUX)
1642 if (RT_SUCCESS(m->hostDrives.updateFloppies()))
1643 for (DriveInfoList::const_iterator it = m->hostDrives.FloppyBegin();
1644 SUCCEEDED(rc) && it != m->hostDrives.FloppyEnd(); ++it)
1645 {
1646 ComObjPtr<Medium> hostFloppyDriveObj;
1647 Bstr location(it->mDevice);
1648 Bstr description(it->mDescription);
1649 if (SUCCEEDED(rc))
1650 rc = hostFloppyDriveObj.createObject();
1651 if (SUCCEEDED(rc))
1652 rc = hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, location, description);
1653 if (SUCCEEDED(rc))
1654 list.push_back(hostFloppyDriveObj);
1655 }
1656#else
1657 NOREF(list);
1658 /* PORTME */
1659#endif
1660 }
1661 catch(std::bad_alloc &)
1662 {
1663 rc = E_OUTOFMEMORY;
1664 }
1665
1666 return rc;
1667}
1668
1669#ifdef VBOX_WITH_USB
1670USBProxyService* Host::usbProxyService()
1671{
1672 return m->pUSBProxyService;
1673}
1674
1675HRESULT Host::addChild(HostUSBDeviceFilter *pChild)
1676{
1677 AutoCaller autoCaller(this);
1678 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1679
1680 AutoWriteLock alock(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1681
1682 m->llChildren.push_back(pChild);
1683
1684 return S_OK;
1685}
1686
1687HRESULT Host::removeChild(HostUSBDeviceFilter *pChild)
1688{
1689 AutoCaller autoCaller(this);
1690 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1691
1692 AutoWriteLock alock(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1693
1694 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
1695 it != m->llChildren.end();
1696 ++it)
1697 {
1698 if (*it == pChild)
1699 {
1700 m->llChildren.erase(it);
1701 break;
1702 }
1703 }
1704
1705 return S_OK;
1706}
1707
1708VirtualBox* Host::parent()
1709{
1710 return m->pParent;
1711}
1712
1713/**
1714 * Called by setter methods of all USB device filters.
1715 */
1716HRESULT Host::onUSBDeviceFilterChange(HostUSBDeviceFilter *aFilter,
1717 BOOL aActiveChanged /* = FALSE */)
1718{
1719 AutoCaller autoCaller(this);
1720 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1721
1722 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1723
1724 if (aFilter->mInList)
1725 {
1726 if (aActiveChanged)
1727 {
1728 // insert/remove the filter from the proxy
1729 if (aFilter->getData().mActive)
1730 {
1731 ComAssertRet(aFilter->getId() == NULL, E_FAIL);
1732 aFilter->getId() = m->pUSBProxyService->insertFilter(&aFilter->getData().mUSBFilter);
1733 }
1734 else
1735 {
1736 ComAssertRet(aFilter->getId() != NULL, E_FAIL);
1737 m->pUSBProxyService->removeFilter(aFilter->getId());
1738 aFilter->getId() = NULL;
1739 }
1740 }
1741 else
1742 {
1743 if (aFilter->getData().mActive)
1744 {
1745 // update the filter in the proxy
1746 ComAssertRet(aFilter->getId() != NULL, E_FAIL);
1747 m->pUSBProxyService->removeFilter(aFilter->getId());
1748 aFilter->getId() = m->pUSBProxyService->insertFilter(&aFilter->getData().mUSBFilter);
1749 }
1750 }
1751
1752 // save the global settings... yeah, on every single filter property change
1753 alock.release();
1754 return m->pParent->saveSettings();
1755 }
1756
1757 return S_OK;
1758}
1759
1760
1761/**
1762 * Interface for obtaining a copy of the USBDeviceFilterList,
1763 * used by the USBProxyService.
1764 *
1765 * @param aGlobalFilters Where to put the global filter list copy.
1766 * @param aMachines Where to put the machine vector.
1767 */
1768void Host::getUSBFilters(Host::USBDeviceFilterList *aGlobalFilters)
1769{
1770 AutoReadLock alock(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1771
1772 *aGlobalFilters = m->llUSBDeviceFilters;
1773}
1774
1775#endif /* VBOX_WITH_USB */
1776
1777// private methods
1778////////////////////////////////////////////////////////////////////////////////
1779
1780#if defined(RT_OS_SOLARIS) && defined(VBOX_USE_LIBHAL)
1781/* Solaris hosts, loading libhal at runtime */
1782
1783/**
1784 * Helper function to query the hal subsystem for information about DVD drives attached to the
1785 * system.
1786 *
1787 * @returns true if information was successfully obtained, false otherwise
1788 * @retval list drives found will be attached to this list
1789 */
1790bool Host::getDVDInfoFromHal(std::list<ComObjPtr<Medium> > &list)
1791{
1792 bool halSuccess = false;
1793 DBusError dbusError;
1794 if (!gLibHalCheckPresence())
1795 return false;
1796 gDBusErrorInit (&dbusError);
1797 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
1798 if (dbusConnection != 0)
1799 {
1800 LibHalContext *halContext = gLibHalCtxNew();
1801 if (halContext != 0)
1802 {
1803 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
1804 {
1805 if (gLibHalCtxInit(halContext, &dbusError))
1806 {
1807 int numDevices;
1808 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
1809 "storage.drive_type", "cdrom",
1810 &numDevices, &dbusError);
1811 if (halDevices != 0)
1812 {
1813 /* Hal is installed and working, so if no devices are reported, assume
1814 that there are none. */
1815 halSuccess = true;
1816 for (int i = 0; i < numDevices; i++)
1817 {
1818 char *devNode = gLibHalDeviceGetPropertyString(halContext,
1819 halDevices[i], "block.device", &dbusError);
1820#ifdef RT_OS_SOLARIS
1821 /* The CD/DVD ioctls work only for raw device nodes. */
1822 char *tmp = getfullrawname(devNode);
1823 gLibHalFreeString(devNode);
1824 devNode = tmp;
1825#endif
1826
1827 if (devNode != 0)
1828 {
1829// if (validateDevice(devNode, true))
1830// {
1831 Utf8Str description;
1832 char *vendor, *product;
1833 /* We do not check the error here, as this field may
1834 not even exist. */
1835 vendor = gLibHalDeviceGetPropertyString(halContext,
1836 halDevices[i], "info.vendor", 0);
1837 product = gLibHalDeviceGetPropertyString(halContext,
1838 halDevices[i], "info.product", &dbusError);
1839 if ((product != 0 && product[0] != 0))
1840 {
1841 if ((vendor != 0) && (vendor[0] != 0))
1842 {
1843 description = Utf8StrFmt ("%s %s",
1844 vendor, product);
1845 }
1846 else
1847 {
1848 description = product;
1849 }
1850 ComObjPtr<Medium> hostDVDDriveObj;
1851 hostDVDDriveObj.createObject();
1852 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
1853 Bstr(devNode), Bstr(description));
1854 list.push_back (hostDVDDriveObj);
1855 }
1856 else
1857 {
1858 if (product == 0)
1859 {
1860 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
1861 halDevices[i], dbusError.name, dbusError.message));
1862 gDBusErrorFree(&dbusError);
1863 }
1864 ComObjPtr<Medium> hostDVDDriveObj;
1865 hostDVDDriveObj.createObject();
1866 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
1867 Bstr(devNode));
1868 list.push_back (hostDVDDriveObj);
1869 }
1870 if (vendor != 0)
1871 {
1872 gLibHalFreeString(vendor);
1873 }
1874 if (product != 0)
1875 {
1876 gLibHalFreeString(product);
1877 }
1878// }
1879// else
1880// {
1881// LogRel(("Host::COMGETTER(DVDDrives): failed to validate the block device %s as a DVD drive\n"));
1882// }
1883#ifndef RT_OS_SOLARIS
1884 gLibHalFreeString(devNode);
1885#else
1886 free(devNode);
1887#endif
1888 }
1889 else
1890 {
1891 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
1892 halDevices[i], dbusError.name, dbusError.message));
1893 gDBusErrorFree(&dbusError);
1894 }
1895 }
1896 gLibHalFreeStringArray(halDevices);
1897 }
1898 else
1899 {
1900 LogRel(("Host::COMGETTER(DVDDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1901 gDBusErrorFree(&dbusError);
1902 }
1903 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
1904 {
1905 LogRel(("Host::COMGETTER(DVDDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1906 gDBusErrorFree(&dbusError);
1907 }
1908 }
1909 else
1910 {
1911 LogRel(("Host::COMGETTER(DVDDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1912 gDBusErrorFree(&dbusError);
1913 }
1914 gLibHalCtxFree(halContext);
1915 }
1916 else
1917 {
1918 LogRel(("Host::COMGETTER(DVDDrives): failed to set libhal connection to dbus.\n"));
1919 }
1920 }
1921 else
1922 {
1923 LogRel(("Host::COMGETTER(DVDDrives): failed to get a libhal context - out of memory?\n"));
1924 }
1925 gDBusConnectionUnref(dbusConnection);
1926 }
1927 else
1928 {
1929 LogRel(("Host::COMGETTER(DVDDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1930 gDBusErrorFree(&dbusError);
1931 }
1932 return halSuccess;
1933}
1934
1935
1936/**
1937 * Helper function to query the hal subsystem for information about floppy drives attached to the
1938 * system.
1939 *
1940 * @returns true if information was successfully obtained, false otherwise
1941 * @retval list drives found will be attached to this list
1942 */
1943bool Host::getFloppyInfoFromHal(std::list< ComObjPtr<Medium> > &list)
1944{
1945 bool halSuccess = false;
1946 DBusError dbusError;
1947 if (!gLibHalCheckPresence())
1948 return false;
1949 gDBusErrorInit (&dbusError);
1950 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
1951 if (dbusConnection != 0)
1952 {
1953 LibHalContext *halContext = gLibHalCtxNew();
1954 if (halContext != 0)
1955 {
1956 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
1957 {
1958 if (gLibHalCtxInit(halContext, &dbusError))
1959 {
1960 int numDevices;
1961 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
1962 "storage.drive_type", "floppy",
1963 &numDevices, &dbusError);
1964 if (halDevices != 0)
1965 {
1966 /* Hal is installed and working, so if no devices are reported, assume
1967 that there are none. */
1968 halSuccess = true;
1969 for (int i = 0; i < numDevices; i++)
1970 {
1971 char *driveType = gLibHalDeviceGetPropertyString(halContext,
1972 halDevices[i], "storage.drive_type", 0);
1973 if (driveType != 0)
1974 {
1975 if (strcmp(driveType, "floppy") != 0)
1976 {
1977 gLibHalFreeString(driveType);
1978 continue;
1979 }
1980 gLibHalFreeString(driveType);
1981 }
1982 else
1983 {
1984 /* An error occurred. The attribute "storage.drive_type"
1985 probably didn't exist. */
1986 continue;
1987 }
1988 char *devNode = gLibHalDeviceGetPropertyString(halContext,
1989 halDevices[i], "block.device", &dbusError);
1990 if (devNode != 0)
1991 {
1992// if (validateDevice(devNode, false))
1993// {
1994 Utf8Str description;
1995 char *vendor, *product;
1996 /* We do not check the error here, as this field may
1997 not even exist. */
1998 vendor = gLibHalDeviceGetPropertyString(halContext,
1999 halDevices[i], "info.vendor", 0);
2000 product = gLibHalDeviceGetPropertyString(halContext,
2001 halDevices[i], "info.product", &dbusError);
2002 if ((product != 0) && (product[0] != 0))
2003 {
2004 if ((vendor != 0) && (vendor[0] != 0))
2005 {
2006 description = Utf8StrFmt ("%s %s",
2007 vendor, product);
2008 }
2009 else
2010 {
2011 description = product;
2012 }
2013 ComObjPtr<Medium> hostFloppyDrive;
2014 hostFloppyDrive.createObject();
2015 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
2016 Bstr(devNode), Bstr(description));
2017 list.push_back (hostFloppyDrive);
2018 }
2019 else
2020 {
2021 if (product == 0)
2022 {
2023 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
2024 halDevices[i], dbusError.name, dbusError.message));
2025 gDBusErrorFree(&dbusError);
2026 }
2027 ComObjPtr<Medium> hostFloppyDrive;
2028 hostFloppyDrive.createObject();
2029 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
2030 Bstr(devNode));
2031 list.push_back (hostFloppyDrive);
2032 }
2033 if (vendor != 0)
2034 {
2035 gLibHalFreeString(vendor);
2036 }
2037 if (product != 0)
2038 {
2039 gLibHalFreeString(product);
2040 }
2041// }
2042// else
2043// {
2044// LogRel(("Host::COMGETTER(FloppyDrives): failed to validate the block device %s as a floppy drive\n"));
2045// }
2046 gLibHalFreeString(devNode);
2047 }
2048 else
2049 {
2050 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
2051 halDevices[i], dbusError.name, dbusError.message));
2052 gDBusErrorFree(&dbusError);
2053 }
2054 }
2055 gLibHalFreeStringArray(halDevices);
2056 }
2057 else
2058 {
2059 LogRel(("Host::COMGETTER(FloppyDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2060 gDBusErrorFree(&dbusError);
2061 }
2062 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
2063 {
2064 LogRel(("Host::COMGETTER(FloppyDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2065 gDBusErrorFree(&dbusError);
2066 }
2067 }
2068 else
2069 {
2070 LogRel(("Host::COMGETTER(FloppyDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2071 gDBusErrorFree(&dbusError);
2072 }
2073 gLibHalCtxFree(halContext);
2074 }
2075 else
2076 {
2077 LogRel(("Host::COMGETTER(FloppyDrives): failed to set libhal connection to dbus.\n"));
2078 }
2079 }
2080 else
2081 {
2082 LogRel(("Host::COMGETTER(FloppyDrives): failed to get a libhal context - out of memory?\n"));
2083 }
2084 gDBusConnectionUnref(dbusConnection);
2085 }
2086 else
2087 {
2088 LogRel(("Host::COMGETTER(FloppyDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2089 gDBusErrorFree(&dbusError);
2090 }
2091 return halSuccess;
2092}
2093#endif /* RT_OS_SOLARIS and VBOX_USE_HAL */
2094
2095/** @todo get rid of dead code below - RT_OS_SOLARIS and RT_OS_LINUX are never both set */
2096#if defined(RT_OS_SOLARIS)
2097
2098/**
2099 * Helper function to parse the given mount file and add found entries
2100 */
2101void Host::parseMountTable(char *mountTable, std::list< ComObjPtr<Medium> > &list)
2102{
2103#ifdef RT_OS_LINUX
2104 FILE *mtab = setmntent(mountTable, "r");
2105 if (mtab)
2106 {
2107 struct mntent *mntent;
2108 char *mnt_type;
2109 char *mnt_dev;
2110 char *tmp;
2111 while ((mntent = getmntent(mtab)))
2112 {
2113 mnt_type = (char*)malloc(strlen(mntent->mnt_type) + 1);
2114 mnt_dev = (char*)malloc(strlen(mntent->mnt_fsname) + 1);
2115 strcpy(mnt_type, mntent->mnt_type);
2116 strcpy(mnt_dev, mntent->mnt_fsname);
2117 // supermount fs case
2118 if (strcmp(mnt_type, "supermount") == 0)
2119 {
2120 tmp = strstr(mntent->mnt_opts, "fs=");
2121 if (tmp)
2122 {
2123 free(mnt_type);
2124 mnt_type = strdup(tmp + strlen("fs="));
2125 if (mnt_type)
2126 {
2127 tmp = strchr(mnt_type, ',');
2128 if (tmp)
2129 *tmp = '\0';
2130 }
2131 }
2132 tmp = strstr(mntent->mnt_opts, "dev=");
2133 if (tmp)
2134 {
2135 free(mnt_dev);
2136 mnt_dev = strdup(tmp + strlen("dev="));
2137 if (mnt_dev)
2138 {
2139 tmp = strchr(mnt_dev, ',');
2140 if (tmp)
2141 *tmp = '\0';
2142 }
2143 }
2144 }
2145 // use strstr here to cover things fs types like "udf,iso9660"
2146 if (strstr(mnt_type, "iso9660") == 0)
2147 {
2148 /** @todo check whether we've already got the drive in our list! */
2149 if (validateDevice(mnt_dev, true))
2150 {
2151 ComObjPtr<Medium> hostDVDDriveObj;
2152 hostDVDDriveObj.createObject();
2153 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(mnt_dev));
2154 list.push_back (hostDVDDriveObj);
2155 }
2156 }
2157 free(mnt_dev);
2158 free(mnt_type);
2159 }
2160 endmntent(mtab);
2161 }
2162#else // RT_OS_SOLARIS
2163 FILE *mntFile = fopen(mountTable, "r");
2164 if (mntFile)
2165 {
2166 struct mnttab mntTab;
2167 while (getmntent(mntFile, &mntTab) == 0)
2168 {
2169 const char *mountName = mntTab.mnt_special;
2170 const char *mountPoint = mntTab.mnt_mountp;
2171 const char *mountFSType = mntTab.mnt_fstype;
2172 if (mountName && mountPoint && mountFSType)
2173 {
2174 // skip devices we are not interested in
2175 if ((*mountName && mountName[0] == '/') && // skip 'fake' devices (like -hosts, proc, fd, swap)
2176 (*mountFSType && (strncmp(mountFSType, "devfs", 5) != 0 && // skip devfs (i.e. /devices)
2177 strncmp(mountFSType, "dev", 3) != 0 && // skip dev (i.e. /dev)
2178 strncmp(mountFSType, "lofs", 4) != 0))) // skip loop-back file-system (lofs)
2179 {
2180 char *rawDevName = getfullrawname((char *)mountName);
2181 if (validateDevice(rawDevName, true))
2182 {
2183 ComObjPtr<Medium> hostDVDDriveObj;
2184 hostDVDDriveObj.createObject();
2185 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(rawDevName));
2186 list.push_back (hostDVDDriveObj);
2187 }
2188 free(rawDevName);
2189 }
2190 }
2191 }
2192
2193 fclose(mntFile);
2194 }
2195#endif
2196}
2197
2198/**
2199 * Helper function to check whether the given device node is a valid drive
2200 */
2201bool Host::validateDevice(const char *deviceNode, bool isCDROM)
2202{
2203 struct stat statInfo;
2204 bool retValue = false;
2205
2206 // sanity check
2207 if (!deviceNode)
2208 {
2209 return false;
2210 }
2211
2212 // first a simple stat() call
2213 if (stat(deviceNode, &statInfo) < 0)
2214 {
2215 return false;
2216 }
2217 else
2218 {
2219 if (isCDROM)
2220 {
2221 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2222 {
2223 int fileHandle;
2224 // now try to open the device
2225 fileHandle = open(deviceNode, O_RDONLY | O_NONBLOCK, 0);
2226 if (fileHandle >= 0)
2227 {
2228 cdrom_subchnl cdChannelInfo;
2229 cdChannelInfo.cdsc_format = CDROM_MSF;
2230 // this call will finally reveal the whole truth
2231#ifdef RT_OS_LINUX
2232 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2233 (errno == EIO) || (errno == ENOENT) ||
2234 (errno == EINVAL) || (errno == ENOMEDIUM))
2235#else
2236 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2237 (errno == EIO) || (errno == ENOENT) ||
2238 (errno == EINVAL))
2239#endif
2240 {
2241 retValue = true;
2242 }
2243 close(fileHandle);
2244 }
2245 }
2246 } else
2247 {
2248 // floppy case
2249 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2250 {
2251 /// @todo do some more testing, maybe a nice IOCTL!
2252 retValue = true;
2253 }
2254 }
2255 }
2256 return retValue;
2257}
2258#endif // RT_OS_SOLARIS
2259
2260#ifdef VBOX_WITH_USB
2261/**
2262 * Checks for the presense and status of the USB Proxy Service.
2263 * Returns S_OK when the Proxy is present and OK, VBOX_E_HOST_ERROR (as a
2264 * warning) if the proxy service is not available due to the way the host is
2265 * configured (at present, that means that usbfs and hal/DBus are not
2266 * available on a Linux host) or E_FAIL and a corresponding error message
2267 * otherwise. Intended to be used by methods that rely on the Proxy Service
2268 * availability.
2269 *
2270 * @note This method may return a warning result code. It is recommended to use
2271 * MultiError to store the return value.
2272 *
2273 * @note Locks this object for reading.
2274 */
2275HRESULT Host::checkUSBProxyService()
2276{
2277 AutoCaller autoCaller(this);
2278 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2279
2280 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2281
2282 AssertReturn(m->pUSBProxyService, E_FAIL);
2283 if (!m->pUSBProxyService->isActive())
2284 {
2285 /* disable the USB controller completely to avoid assertions if the
2286 * USB proxy service could not start. */
2287
2288 if (m->pUSBProxyService->getLastError() == VERR_FILE_NOT_FOUND)
2289 return setWarning (E_FAIL,
2290 tr ("Could not load the Host USB Proxy Service (%Rrc). "
2291 "The service might not be installed on the host computer"),
2292 m->pUSBProxyService->getLastError());
2293 if (m->pUSBProxyService->getLastError() == VINF_SUCCESS)
2294#ifdef RT_OS_LINUX
2295 return setWarning (VBOX_E_HOST_ERROR,
2296# ifdef VBOX_WITH_DBUS
2297 tr ("The USB Proxy Service could not be started, because neither the USB file system (usbfs) nor the hardware information service (hal) is available")
2298# else
2299 tr ("The USB Proxy Service could not be started, because the USB file system (usbfs) is not available")
2300# endif
2301 );
2302#else /* !RT_OS_LINUX */
2303 return setWarning (E_FAIL,
2304 tr ("The USB Proxy Service has not yet been ported to this host"));
2305#endif /* !RT_OS_LINUX */
2306 return setWarning (E_FAIL,
2307 tr ("Could not load the Host USB Proxy service (%Rrc)"),
2308 m->pUSBProxyService->getLastError());
2309 }
2310
2311 return S_OK;
2312}
2313#endif /* VBOX_WITH_USB */
2314
2315#ifdef VBOX_WITH_RESOURCE_USAGE_API
2316void Host::registerMetrics(PerformanceCollector *aCollector)
2317{
2318 pm::CollectorHAL *hal = aCollector->getHAL();
2319 /* Create sub metrics */
2320 pm::SubMetric *cpuLoadUser = new pm::SubMetric("CPU/Load/User",
2321 "Percentage of processor time spent in user mode.");
2322 pm::SubMetric *cpuLoadKernel = new pm::SubMetric("CPU/Load/Kernel",
2323 "Percentage of processor time spent in kernel mode.");
2324 pm::SubMetric *cpuLoadIdle = new pm::SubMetric("CPU/Load/Idle",
2325 "Percentage of processor time spent idling.");
2326 pm::SubMetric *cpuMhzSM = new pm::SubMetric("CPU/MHz",
2327 "Average of current frequency of all processors.");
2328 pm::SubMetric *ramUsageTotal = new pm::SubMetric("RAM/Usage/Total",
2329 "Total physical memory installed.");
2330 pm::SubMetric *ramUsageUsed = new pm::SubMetric("RAM/Usage/Used",
2331 "Physical memory currently occupied.");
2332 pm::SubMetric *ramUsageFree = new pm::SubMetric("RAM/Usage/Free",
2333 "Physical memory currently available to applications.");
2334 pm::SubMetric *ramVMMUsed = new pm::SubMetric("RAM/VMM/Used",
2335 "Total physical memory used by the hypervisor.");
2336 pm::SubMetric *ramVMMFree = new pm::SubMetric("RAM/VMM/Free",
2337 "Total physical memory free inside the hypervisor.");
2338 pm::SubMetric *ramVMMBallooned = new pm::SubMetric("RAM/VMM/Ballooned",
2339 "Total physical memory ballooned by the hypervisor.");
2340
2341
2342 /* Create and register base metrics */
2343 IUnknown *objptr;
2344 ComObjPtr<Host> tmp = this;
2345 tmp.queryInterfaceTo(&objptr);
2346 pm::BaseMetric *cpuLoad = new pm::HostCpuLoadRaw(hal, objptr, cpuLoadUser, cpuLoadKernel,
2347 cpuLoadIdle);
2348 aCollector->registerBaseMetric (cpuLoad);
2349 pm::BaseMetric *cpuMhz = new pm::HostCpuMhz(hal, objptr, cpuMhzSM);
2350 aCollector->registerBaseMetric (cpuMhz);
2351 pm::BaseMetric *ramUsage = new pm::HostRamUsage(hal, objptr, ramUsageTotal, ramUsageUsed,
2352 ramUsageFree, ramVMMUsed, ramVMMFree, ramVMMBallooned);
2353 aCollector->registerBaseMetric (ramUsage);
2354
2355 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser, 0));
2356 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
2357 new pm::AggregateAvg()));
2358 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
2359 new pm::AggregateMin()));
2360 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
2361 new pm::AggregateMax()));
2362
2363 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel, 0));
2364 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
2365 new pm::AggregateAvg()));
2366 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
2367 new pm::AggregateMin()));
2368 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
2369 new pm::AggregateMax()));
2370
2371 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle, 0));
2372 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
2373 new pm::AggregateAvg()));
2374 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
2375 new pm::AggregateMin()));
2376 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
2377 new pm::AggregateMax()));
2378
2379 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM, 0));
2380 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
2381 new pm::AggregateAvg()));
2382 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
2383 new pm::AggregateMin()));
2384 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
2385 new pm::AggregateMax()));
2386
2387 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal, 0));
2388 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
2389 new pm::AggregateAvg()));
2390 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
2391 new pm::AggregateMin()));
2392 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
2393 new pm::AggregateMax()));
2394
2395 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed, 0));
2396 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
2397 new pm::AggregateAvg()));
2398 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
2399 new pm::AggregateMin()));
2400 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
2401 new pm::AggregateMax()));
2402
2403 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree, 0));
2404 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
2405 new pm::AggregateAvg()));
2406 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
2407 new pm::AggregateMin()));
2408 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
2409 new pm::AggregateMax()));
2410
2411 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMUsed, 0));
2412 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMUsed,
2413 new pm::AggregateAvg()));
2414 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMUsed,
2415 new pm::AggregateMin()));
2416 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMUsed,
2417 new pm::AggregateMax()));
2418
2419 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMFree, 0));
2420 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMFree,
2421 new pm::AggregateAvg()));
2422 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMFree,
2423 new pm::AggregateMin()));
2424 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMFree,
2425 new pm::AggregateMax()));
2426
2427 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMBallooned, 0));
2428 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMBallooned,
2429 new pm::AggregateAvg()));
2430 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMBallooned,
2431 new pm::AggregateMin()));
2432 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMBallooned,
2433 new pm::AggregateMax()));
2434};
2435
2436void Host::unregisterMetrics (PerformanceCollector *aCollector)
2437{
2438 aCollector->unregisterMetricsFor(this);
2439 aCollector->unregisterBaseMetricsFor(this);
2440};
2441#endif /* VBOX_WITH_RESOURCE_USAGE_API */
2442
2443/* 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