VirtualBox

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

Last change on this file since 30787 was 30764, checked in by vboxsync, 14 years ago

back out r63543, r63544 until windows build problems can be solved properly

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