VirtualBox

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

Last change on this file since 29940 was 29620, checked in by vboxsync, 15 years ago

Statistics for shared pages

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 83.9 KB
Line 
1/* $Id: HostImpl.cpp 29620 2010-05-18 12:15:55Z 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#include "HostImpl.h"
22
23#ifdef VBOX_WITH_USB
24# include "HostUSBDeviceImpl.h"
25# include "USBDeviceFilterImpl.h"
26# include "USBProxyService.h"
27#endif // VBOX_WITH_USB
28
29#include "HostNetworkInterfaceImpl.h"
30#include "MachineImpl.h"
31#include "AutoCaller.h"
32#include "Logging.h"
33#include "Performance.h"
34
35#include "MediumImpl.h"
36#include "HostPower.h"
37
38#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
39# include <HostHardwareLinux.h>
40#endif
41
42#ifdef VBOX_WITH_RESOURCE_USAGE_API
43# include "PerformanceImpl.h"
44#endif /* VBOX_WITH_RESOURCE_USAGE_API */
45
46#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
47# include <VBox/WinNetConfig.h>
48#endif /* #if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT) */
49
50#ifdef RT_OS_LINUX
51# include <sys/ioctl.h>
52# include <errno.h>
53# include <net/if.h>
54# include <net/if_arp.h>
55#endif /* RT_OS_LINUX */
56
57#ifdef RT_OS_SOLARIS
58# include <fcntl.h>
59# include <unistd.h>
60# include <stropts.h>
61# include <errno.h>
62# include <limits.h>
63# include <stdio.h>
64# ifdef VBOX_SOLARIS_NSL_RESOLVED
65# include <libdevinfo.h>
66# endif
67# include <net/if.h>
68# include <sys/socket.h>
69# include <sys/sockio.h>
70# include <net/if_arp.h>
71# include <net/if.h>
72# include <sys/types.h>
73# include <sys/stat.h>
74# include <sys/cdio.h>
75# include <sys/dkio.h>
76# include <sys/mnttab.h>
77# include <sys/mntent.h>
78/* Dynamic loading of libhal on Solaris hosts */
79# ifdef VBOX_USE_LIBHAL
80# include "vbox-libhal.h"
81extern "C" char *getfullrawname(char *);
82# endif
83# include "solaris/DynLoadLibSolaris.h"
84#endif /* RT_OS_SOLARIS */
85
86#ifdef RT_OS_WINDOWS
87# define _WIN32_DCOM
88# include <windows.h>
89# include <shellapi.h>
90# define INITGUID
91# include <guiddef.h>
92# include <devguid.h>
93# include <objbase.h>
94//# include <setupapi.h>
95# include <shlobj.h>
96# include <cfgmgr32.h>
97
98#endif /* RT_OS_WINDOWS */
99
100#ifdef RT_OS_DARWIN
101# include "darwin/iokit.h"
102#endif
103
104#ifdef VBOX_WITH_CROGL
105extern bool is3DAccelerationSupported();
106#endif /* VBOX_WITH_CROGL */
107
108#include <iprt/asm-amd64-x86.h>
109#include <iprt/string.h>
110#include <iprt/mp.h>
111#include <iprt/time.h>
112#include <iprt/param.h>
113#include <iprt/env.h>
114#include <iprt/mem.h>
115#include <iprt/system.h>
116#ifdef RT_OS_SOLARIS
117# include <iprt/path.h>
118# include <iprt/ctype.h>
119#endif
120#ifdef VBOX_WITH_HOSTNETIF_API
121# include "netif.h"
122#endif
123
124/* XXX Solaris: definitions in /usr/include/sys/regset.h clash with hwacc_svm.h */
125#undef DS
126#undef ES
127#undef CS
128#undef SS
129#undef FS
130#undef GS
131
132#include <VBox/usb.h>
133#include <VBox/x86.h>
134#include <VBox/hwacc_svm.h>
135#include <VBox/err.h>
136#include <VBox/settings.h>
137#include <VBox/sup.h>
138
139#include <stdio.h>
140
141#include <algorithm>
142
143
144////////////////////////////////////////////////////////////////////////////////
145//
146// Host private data definition
147//
148////////////////////////////////////////////////////////////////////////////////
149
150struct Host::Data
151{
152 Data()
153#ifdef VBOX_WITH_USB
154 : usbListsLock(LOCKCLASS_USBLIST)
155#endif
156 {};
157
158 VirtualBox *pParent;
159
160#ifdef VBOX_WITH_USB
161 WriteLockHandle usbListsLock; // protects the below two lists
162
163 USBDeviceFilterList llChildren; // all USB device filters
164 USBDeviceFilterList llUSBDeviceFilters; // USB device filters in use by the USB proxy service
165
166 /** Pointer to the USBProxyService object. */
167 USBProxyService *pUSBProxyService;
168#endif /* VBOX_WITH_USB */
169
170#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
171 /** Object with information about host drives */
172 VBoxMainDriveInfo hostDrives;
173#endif
174 /* Features that can be queried with GetProcessorFeature */
175 BOOL fVTSupported,
176 fLongModeSupported,
177 fPAESupported,
178 fNestedPagingSupported;
179
180 /* 3D hardware acceleration supported? */
181 BOOL f3DAccelerationSupported;
182
183 HostPowerService *pHostPowerService;
184};
185
186
187////////////////////////////////////////////////////////////////////////////////
188//
189// Constructor / destructor
190//
191////////////////////////////////////////////////////////////////////////////////
192
193HRESULT Host::FinalConstruct()
194{
195 return S_OK;
196}
197
198void Host::FinalRelease()
199{
200 uninit();
201}
202
203/**
204 * Initializes the host object.
205 *
206 * @param aParent VirtualBox parent object.
207 */
208HRESULT Host::init(VirtualBox *aParent)
209{
210 LogFlowThisFunc(("aParent=%p\n", aParent));
211
212 /* Enclose the state transition NotReady->InInit->Ready */
213 AutoInitSpan autoInitSpan(this);
214 AssertReturn(autoInitSpan.isOk(), E_FAIL);
215
216 m = new Data();
217
218 m->pParent = aParent;
219
220#ifdef VBOX_WITH_USB
221 /*
222 * Create and initialize the USB Proxy Service.
223 */
224# if defined (RT_OS_DARWIN)
225 m->pUSBProxyService = new USBProxyServiceDarwin(this);
226# elif defined (RT_OS_LINUX)
227 m->pUSBProxyService = new USBProxyServiceLinux(this);
228# elif defined (RT_OS_OS2)
229 m->pUSBProxyService = new USBProxyServiceOs2 (this);
230# elif defined (RT_OS_SOLARIS)
231 m->pUSBProxyService = new USBProxyServiceSolaris(this);
232# elif defined (RT_OS_WINDOWS)
233 m->pUSBProxyService = new USBProxyServiceWindows(this);
234# elif defined (RT_OS_FREEBSD)
235 m->pUSBProxyService = new USBProxyServiceFreeBSD(this);
236# else
237 m->pUSBProxyService = new USBProxyService(this);
238# endif
239 HRESULT hrc = m->pUSBProxyService->init();
240 AssertComRCReturn(hrc, hrc);
241#endif /* VBOX_WITH_USB */
242
243#ifdef VBOX_WITH_RESOURCE_USAGE_API
244 registerMetrics(aParent->performanceCollector());
245#endif /* VBOX_WITH_RESOURCE_USAGE_API */
246
247#if defined (RT_OS_WINDOWS)
248 m->pHostPowerService = new HostPowerServiceWin(m->pParent);
249#elif defined (RT_OS_DARWIN)
250 m->pHostPowerService = new HostPowerServiceDarwin(m->pParent);
251#else
252 m->pHostPowerService = new HostPowerService(m->pParent);
253#endif
254
255 /* Cache the features reported by GetProcessorFeature. */
256 m->fVTSupported = false;
257 m->fLongModeSupported = false;
258 m->fPAESupported = false;
259 m->fNestedPagingSupported = false;
260
261 if (ASMHasCpuId())
262 {
263 uint32_t u32FeaturesECX;
264 uint32_t u32Dummy;
265 uint32_t u32FeaturesEDX;
266 uint32_t u32VendorEBX, u32VendorECX, u32VendorEDX, u32AMDFeatureEDX, u32AMDFeatureECX;
267
268 ASMCpuId(0, &u32Dummy, &u32VendorEBX, &u32VendorECX, &u32VendorEDX);
269 ASMCpuId(1, &u32Dummy, &u32Dummy, &u32FeaturesECX, &u32FeaturesEDX);
270 /* Query AMD features. */
271 ASMCpuId(0x80000001, &u32Dummy, &u32Dummy, &u32AMDFeatureECX, &u32AMDFeatureEDX);
272
273 m->fLongModeSupported = !!(u32AMDFeatureEDX & X86_CPUID_AMD_FEATURE_EDX_LONG_MODE);
274 m->fPAESupported = !!(u32FeaturesEDX & X86_CPUID_FEATURE_EDX_PAE);
275
276 if ( u32VendorEBX == X86_CPUID_VENDOR_INTEL_EBX
277 && u32VendorECX == X86_CPUID_VENDOR_INTEL_ECX
278 && u32VendorEDX == X86_CPUID_VENDOR_INTEL_EDX
279 )
280 {
281 if ( (u32FeaturesECX & X86_CPUID_FEATURE_ECX_VMX)
282 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR)
283 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR)
284 )
285 {
286 int rc = SUPR3QueryVTxSupported();
287 if (RT_SUCCESS(rc))
288 m->fVTSupported = true;
289 }
290 }
291 else
292 if ( u32VendorEBX == X86_CPUID_VENDOR_AMD_EBX
293 && u32VendorECX == X86_CPUID_VENDOR_AMD_ECX
294 && u32VendorEDX == X86_CPUID_VENDOR_AMD_EDX
295 )
296 {
297 if ( (u32AMDFeatureECX & X86_CPUID_AMD_FEATURE_ECX_SVM)
298 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR)
299 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR)
300 )
301 {
302 uint32_t u32SVMFeatureEDX;
303
304 m->fVTSupported = true;
305
306 /* Query AMD features. */
307 ASMCpuId(0x8000000A, &u32Dummy, &u32Dummy, &u32Dummy, &u32SVMFeatureEDX);
308 if (u32SVMFeatureEDX & AMD_CPUID_SVM_FEATURE_EDX_NESTED_PAGING)
309 m->fNestedPagingSupported = true;
310 }
311 }
312 }
313
314#if 0 /* needs testing */
315 if (m->fVTSupported)
316 {
317 uint32_t u32Caps = 0;
318
319 int rc = SUPR3QueryVTCaps(&u32Caps);
320 if (RT_SUCCESS(rc))
321 {
322 if (u32Caps & SUPVTCAPS_NESTED_PAGING)
323 m->fNestedPagingSupported = true;
324 }
325 /* else @todo; report BIOS trouble in some way. */
326 }
327#endif
328
329 /* Test for 3D hardware acceleration support */
330 m->f3DAccelerationSupported = false;
331
332#ifdef VBOX_WITH_CROGL
333 m->f3DAccelerationSupported = is3DAccelerationSupported();
334#endif /* VBOX_WITH_CROGL */
335
336 /* Confirm a successful initialization */
337 autoInitSpan.setSucceeded();
338
339 return S_OK;
340}
341
342/**
343 * Uninitializes the host object and sets the ready flag to FALSE.
344 * Called either from FinalRelease() or by the parent when it gets destroyed.
345 */
346void Host::uninit()
347{
348 LogFlowThisFunc(("\n"));
349
350 /* Enclose the state transition Ready->InUninit->NotReady */
351 AutoUninitSpan autoUninitSpan(this);
352 if (autoUninitSpan.uninitDone())
353 return;
354
355#ifdef VBOX_WITH_RESOURCE_USAGE_API
356 unregisterMetrics (m->pParent->performanceCollector());
357#endif /* VBOX_WITH_RESOURCE_USAGE_API */
358
359#ifdef VBOX_WITH_USB
360 /* wait for USB proxy service to terminate before we uninit all USB
361 * devices */
362 LogFlowThisFunc(("Stopping USB proxy service...\n"));
363 delete m->pUSBProxyService;
364 m->pUSBProxyService = NULL;
365 LogFlowThisFunc(("Done stopping USB proxy service.\n"));
366#endif
367
368 delete m->pHostPowerService;
369
370#ifdef VBOX_WITH_USB
371 /* uninit all USB device filters still referenced by clients
372 * Note! HostUSBDeviceFilter::uninit() will modify llChildren. */
373 while (!m->llChildren.empty())
374 {
375 ComObjPtr<HostUSBDeviceFilter> &pChild = m->llChildren.front();
376 pChild->uninit();
377 }
378
379 m->llUSBDeviceFilters.clear();
380#endif
381
382 delete m;
383 m = NULL;
384}
385
386////////////////////////////////////////////////////////////////////////////////
387//
388// ISnapshot public methods
389//
390////////////////////////////////////////////////////////////////////////////////
391
392/**
393 * Returns a list of host DVD drives.
394 *
395 * @returns COM status code
396 * @param drives address of result pointer
397 */
398STDMETHODIMP Host::COMGETTER(DVDDrives)(ComSafeArrayOut(IMedium *, aDrives))
399{
400 CheckComArgOutSafeArrayPointerValid(aDrives);
401
402 AutoCaller autoCaller(this);
403 if (FAILED(autoCaller.rc())) return autoCaller.rc();
404
405 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
406
407 MediaList list;
408 HRESULT rc = getDVDDrives(list);
409 if (SUCCEEDED(rc))
410 {
411 SafeIfaceArray<IMedium> array(list);
412 array.detachTo(ComSafeArrayOutArg(aDrives));
413 }
414
415 return rc;
416}
417
418/**
419 * Returns a list of host floppy drives.
420 *
421 * @returns COM status code
422 * @param drives address of result pointer
423 */
424STDMETHODIMP Host::COMGETTER(FloppyDrives)(ComSafeArrayOut(IMedium *, aDrives))
425{
426 CheckComArgOutPointerValid(aDrives);
427
428 AutoCaller autoCaller(this);
429 if (FAILED(autoCaller.rc())) return autoCaller.rc();
430
431 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
432
433 MediaList list;
434 HRESULT rc = getFloppyDrives(list);
435 if (SUCCEEDED(rc))
436 {
437 SafeIfaceArray<IMedium> collection(list);
438 collection.detachTo(ComSafeArrayOutArg(aDrives));
439 }
440
441 return rc;
442}
443
444
445#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
446# define VBOX_APP_NAME L"VirtualBox"
447
448static int vboxNetWinAddComponent(std::list< ComObjPtr<HostNetworkInterface> > *pPist,
449 INetCfgComponent *pncc)
450{
451 LPWSTR lpszName;
452 GUID IfGuid;
453 HRESULT hr;
454 int rc = VERR_GENERAL_FAILURE;
455
456 hr = pncc->GetDisplayName( &lpszName );
457 Assert(hr == S_OK);
458 if (hr == S_OK)
459 {
460 Bstr name((CBSTR)lpszName);
461
462 hr = pncc->GetInstanceGuid(&IfGuid);
463 Assert(hr == S_OK);
464 if (hr == S_OK)
465 {
466 /* create a new object and add it to the list */
467 ComObjPtr<HostNetworkInterface> iface;
468 iface.createObject();
469 /* remove the curly bracket at the end */
470 if (SUCCEEDED(iface->init (name, Guid (IfGuid), HostNetworkInterfaceType_Bridged)))
471 {
472// iface->setVirtualBox(m->pParent);
473 pPist->push_back(iface);
474 rc = VINF_SUCCESS;
475 }
476 else
477 {
478 Assert(0);
479 }
480 }
481 CoTaskMemFree(lpszName);
482 }
483
484 return rc;
485}
486#endif /* defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT) */
487
488/**
489 * Returns a list of host network interfaces.
490 *
491 * @returns COM status code
492 * @param drives address of result pointer
493 */
494STDMETHODIMP Host::COMGETTER(NetworkInterfaces)(ComSafeArrayOut(IHostNetworkInterface*, aNetworkInterfaces))
495{
496#if defined(RT_OS_WINDOWS) || defined(VBOX_WITH_NETFLT) /*|| defined(RT_OS_OS2)*/
497 if (ComSafeArrayOutIsNull(aNetworkInterfaces))
498 return E_POINTER;
499
500 AutoCaller autoCaller(this);
501 if (FAILED(autoCaller.rc())) return autoCaller.rc();
502
503 /* The code is so hideously complicated that I can't tell whether the
504 * host object lock is really needed. It was taken here, and as the
505 * VirtualBox (mParent) is taken as well below nested deep down that
506 * would be a lock order violation. */
507 AutoMultiWriteLock2 alock(m->pParent, 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 number of installed physical processor cores.
771 *
772 * @returns COM status code
773 * @param count address of result variable
774 */
775STDMETHODIMP Host::COMGETTER(ProcessorCoreCount)(ULONG *aCount)
776{
777 CheckComArgOutPointerValid(aCount);
778 // no locking required
779
780 return E_NOTIMPL;
781}
782
783/**
784 * Returns the (approximate) maximum speed of the given host CPU in MHz
785 *
786 * @returns COM status code
787 * @param cpu id to get info for.
788 * @param speed address of result variable, speed is 0 if unknown or aCpuId is invalid.
789 */
790STDMETHODIMP Host::GetProcessorSpeed(ULONG aCpuId, ULONG *aSpeed)
791{
792 CheckComArgOutPointerValid(aSpeed);
793 // no locking required
794
795 *aSpeed = RTMpGetMaxFrequency(aCpuId);
796 return S_OK;
797}
798
799/**
800 * Returns a description string for the host CPU
801 *
802 * @returns COM status code
803 * @param cpu id to get info for.
804 * @param description address of result variable, empty string if not known or aCpuId is invalid.
805 */
806STDMETHODIMP Host::GetProcessorDescription(ULONG aCpuId, BSTR *aDescription)
807{
808 CheckComArgOutPointerValid(aDescription);
809 // no locking required
810
811 char szCPUModel[80];
812 int vrc = RTMpGetDescription(aCpuId, szCPUModel, sizeof(szCPUModel));
813 if (RT_FAILURE(vrc))
814 return E_FAIL; /** @todo error reporting? */
815 Bstr (szCPUModel).cloneTo(aDescription);
816 return S_OK;
817}
818
819/**
820 * Returns whether a host processor feature is supported or not
821 *
822 * @returns COM status code
823 * @param Feature to query.
824 * @param address of supported bool result variable
825 */
826STDMETHODIMP Host::GetProcessorFeature(ProcessorFeature_T aFeature, BOOL *aSupported)
827{
828 CheckComArgOutPointerValid(aSupported);
829 AutoCaller autoCaller(this);
830 if (FAILED(autoCaller.rc())) return autoCaller.rc();
831
832 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
833
834 switch (aFeature)
835 {
836 case ProcessorFeature_HWVirtEx:
837 *aSupported = m->fVTSupported;
838 break;
839
840 case ProcessorFeature_PAE:
841 *aSupported = m->fPAESupported;
842 break;
843
844 case ProcessorFeature_LongMode:
845 *aSupported = m->fLongModeSupported;
846 break;
847
848 case ProcessorFeature_NestedPaging:
849 *aSupported = m->fNestedPagingSupported;
850 break;
851
852 default:
853 ReturnComNotImplemented();
854 }
855 return S_OK;
856}
857
858/**
859 * Returns the specific CPUID leaf.
860 *
861 * @returns COM status code
862 * @param aCpuId The CPU number. Mostly ignored.
863 * @param aLeaf The leaf number.
864 * @param aSubLeaf The sub-leaf number.
865 * @param aValEAX Where to return EAX.
866 * @param aValEBX Where to return EBX.
867 * @param aValECX Where to return ECX.
868 * @param aValEDX Where to return EDX.
869 */
870STDMETHODIMP Host::GetProcessorCPUIDLeaf(ULONG aCpuId, ULONG aLeaf, ULONG aSubLeaf,
871 ULONG *aValEAX, ULONG *aValEBX, ULONG *aValECX, ULONG *aValEDX)
872{
873 CheckComArgOutPointerValid(aValEAX);
874 CheckComArgOutPointerValid(aValEBX);
875 CheckComArgOutPointerValid(aValECX);
876 CheckComArgOutPointerValid(aValEDX);
877 // no locking required
878
879 /* Check that the CPU is online. */
880 /** @todo later use RTMpOnSpecific. */
881 if (!RTMpIsCpuOnline(aCpuId))
882 return RTMpIsCpuPresent(aCpuId)
883 ? setError(E_FAIL, tr("CPU no.%u is not present"), aCpuId)
884 : setError(E_FAIL, tr("CPU no.%u is not online"), aCpuId);
885
886 uint32_t uEAX, uEBX, uECX, uEDX;
887 ASMCpuId_Idx_ECX(aLeaf, aSubLeaf, &uEAX, &uEBX, &uECX, &uEDX);
888 *aValEAX = uEAX;
889 *aValEBX = uEBX;
890 *aValECX = uECX;
891 *aValEDX = uEDX;
892
893 return S_OK;
894}
895
896/**
897 * Returns the amount of installed system memory in megabytes
898 *
899 * @returns COM status code
900 * @param size address of result variable
901 */
902STDMETHODIMP Host::COMGETTER(MemorySize)(ULONG *aSize)
903{
904 CheckComArgOutPointerValid(aSize);
905 // no locking required
906
907 /* @todo This is an ugly hack. There must be a function in IPRT for that. */
908 pm::CollectorHAL *hal = pm::createHAL();
909 if (!hal)
910 return E_FAIL;
911 ULONG tmp;
912 int rc = hal->getHostMemoryUsage(aSize, &tmp, &tmp);
913 *aSize /= 1024;
914 delete hal;
915 return rc;
916}
917
918/**
919 * Returns the current system memory free space in megabytes
920 *
921 * @returns COM status code
922 * @param available address of result variable
923 */
924STDMETHODIMP Host::COMGETTER(MemoryAvailable)(ULONG *aAvailable)
925{
926 CheckComArgOutPointerValid(aAvailable);
927 // no locking required
928
929 /* @todo This is an ugly hack. There must be a function in IPRT for that. */
930 pm::CollectorHAL *hal = pm::createHAL();
931 if (!hal)
932 return E_FAIL;
933 ULONG tmp;
934 int rc = hal->getHostMemoryUsage(&tmp, &tmp, aAvailable);
935 *aAvailable /= 1024;
936 delete hal;
937 return rc;
938}
939
940/**
941 * Returns the name string of the host operating system
942 *
943 * @returns COM status code
944 * @param os address of result variable
945 */
946STDMETHODIMP Host::COMGETTER(OperatingSystem)(BSTR *aOs)
947{
948 CheckComArgOutPointerValid(aOs);
949 // no locking required
950
951 char szOSName[80];
952 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szOSName, sizeof(szOSName));
953 if (RT_FAILURE(vrc))
954 return E_FAIL; /** @todo error reporting? */
955 Bstr (szOSName).cloneTo(aOs);
956 return S_OK;
957}
958
959/**
960 * Returns the version string of the host operating system
961 *
962 * @returns COM status code
963 * @param os address of result variable
964 */
965STDMETHODIMP Host::COMGETTER(OSVersion)(BSTR *aVersion)
966{
967 CheckComArgOutPointerValid(aVersion);
968 // no locking required
969
970 /* Get the OS release. Reserve some buffer space for the service pack. */
971 char szOSRelease[128];
972 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOSRelease, sizeof(szOSRelease) - 32);
973 if (RT_FAILURE(vrc))
974 return E_FAIL; /** @todo error reporting? */
975
976 /* Append the service pack if present. */
977 char szOSServicePack[80];
978 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szOSServicePack, sizeof(szOSServicePack));
979 if (RT_FAILURE(vrc))
980 {
981 if (vrc != VERR_NOT_SUPPORTED)
982 return E_FAIL; /** @todo error reporting? */
983 szOSServicePack[0] = '\0';
984 }
985 if (szOSServicePack[0] != '\0')
986 {
987 char *psz = strchr(szOSRelease, '\0');
988 RTStrPrintf(psz, &szOSRelease[sizeof(szOSRelease)] - psz, "sp%s", szOSServicePack);
989 }
990
991 Bstr(szOSRelease).cloneTo(aVersion);
992 return S_OK;
993}
994
995/**
996 * Returns the current host time in milliseconds since 1970-01-01 UTC.
997 *
998 * @returns COM status code
999 * @param time address of result variable
1000 */
1001STDMETHODIMP Host::COMGETTER(UTCTime)(LONG64 *aUTCTime)
1002{
1003 CheckComArgOutPointerValid(aUTCTime);
1004 // no locking required
1005
1006 RTTIMESPEC now;
1007 *aUTCTime = RTTimeSpecGetMilli(RTTimeNow(&now));
1008
1009 return S_OK;
1010}
1011
1012STDMETHODIMP Host::COMGETTER(Acceleration3DAvailable)(BOOL *aSupported)
1013{
1014 CheckComArgOutPointerValid(aSupported);
1015 AutoCaller autoCaller(this);
1016 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1017
1018 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1019
1020 *aSupported = m->f3DAccelerationSupported;
1021
1022 return S_OK;
1023}
1024
1025STDMETHODIMP Host::CreateHostOnlyNetworkInterface(IHostNetworkInterface **aHostNetworkInterface,
1026 IProgress **aProgress)
1027{
1028 CheckComArgOutPointerValid(aHostNetworkInterface);
1029 CheckComArgOutPointerValid(aProgress);
1030
1031 AutoCaller autoCaller(this);
1032 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1033
1034 /* No need to lock anything. If there ever will - watch out, the function
1035 * called below grabs the VirtualBox lock. */
1036
1037 int r = NetIfCreateHostOnlyNetworkInterface(m->pParent, aHostNetworkInterface, aProgress);
1038 if (RT_SUCCESS(r))
1039 return S_OK;
1040
1041 return r == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
1042}
1043
1044STDMETHODIMP Host::RemoveHostOnlyNetworkInterface(IN_BSTR aId,
1045 IProgress **aProgress)
1046{
1047 CheckComArgOutPointerValid(aProgress);
1048
1049 AutoCaller autoCaller(this);
1050 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1051
1052 /* No need to lock anything, the code below does not touch the state
1053 * of the host object. If that ever changes then check for lock order
1054 * violations with the called functions. */
1055
1056 /* first check whether an interface with the given name already exists */
1057 {
1058 ComPtr<IHostNetworkInterface> iface;
1059 if (FAILED(FindHostNetworkInterfaceById(aId,
1060 iface.asOutParam())))
1061 return setError(VBOX_E_OBJECT_NOT_FOUND,
1062 tr("Host network interface with UUID {%RTuuid} does not exist"),
1063 Guid (aId).raw());
1064 }
1065
1066 int r = NetIfRemoveHostOnlyNetworkInterface(m->pParent, Guid(aId), aProgress);
1067 if (RT_SUCCESS(r))
1068 return S_OK;
1069
1070 return r == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
1071}
1072
1073STDMETHODIMP Host::CreateUSBDeviceFilter(IN_BSTR aName,
1074 IHostUSBDeviceFilter **aFilter)
1075{
1076#ifdef VBOX_WITH_USB
1077 CheckComArgStrNotEmptyOrNull(aName);
1078 CheckComArgOutPointerValid(aFilter);
1079
1080 AutoCaller autoCaller(this);
1081 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1082
1083 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1084
1085 ComObjPtr<HostUSBDeviceFilter> filter;
1086 filter.createObject();
1087 HRESULT rc = filter->init(this, aName);
1088 ComAssertComRCRet(rc, rc);
1089 rc = filter.queryInterfaceTo(aFilter);
1090 AssertComRCReturn(rc, rc);
1091 return S_OK;
1092#else
1093 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1094 * extended error info to indicate that USB is simply not available
1095 * (w/o treating it as a failure), for example, as in OSE. */
1096 NOREF(aName);
1097 NOREF(aFilter);
1098 ReturnComNotImplemented();
1099#endif
1100}
1101
1102STDMETHODIMP Host::InsertUSBDeviceFilter(ULONG aPosition,
1103 IHostUSBDeviceFilter *aFilter)
1104{
1105#ifdef VBOX_WITH_USB
1106 CheckComArgNotNull(aFilter);
1107
1108 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1109 AutoCaller autoCaller(this);
1110 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1111
1112 AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1113
1114 MultiResult rc = checkUSBProxyService();
1115 if (FAILED(rc)) return rc;
1116
1117 ComObjPtr<HostUSBDeviceFilter> pFilter;
1118 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
1119 it != m->llChildren.end();
1120 ++it)
1121 {
1122 if (*it == aFilter)
1123 {
1124 pFilter = *it;
1125 break;
1126 }
1127 }
1128 if (pFilter.isNull())
1129 return setError(VBOX_E_INVALID_OBJECT_STATE,
1130 tr("The given USB device filter is not created within this VirtualBox instance"));
1131
1132 if (pFilter->mInList)
1133 return setError(E_INVALIDARG,
1134 tr("The given USB device filter is already in the list"));
1135
1136 /* iterate to the position... */
1137 USBDeviceFilterList::iterator itPos = m->llUSBDeviceFilters.begin();
1138 std::advance(itPos, aPosition);
1139 /* ...and insert */
1140 m->llUSBDeviceFilters.insert(itPos, pFilter);
1141 pFilter->mInList = true;
1142
1143 /* notify the proxy (only when the filter is active) */
1144 if ( m->pUSBProxyService->isActive()
1145 && pFilter->getData().mActive)
1146 {
1147 ComAssertRet(pFilter->getId() == NULL, E_FAIL);
1148 pFilter->getId() = m->pUSBProxyService->insertFilter(&pFilter->getData().mUSBFilter);
1149 }
1150
1151 /* save the global settings */
1152 alock.release();
1153 return rc = m->pParent->saveSettings();
1154#else
1155 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1156 * extended error info to indicate that USB is simply not available
1157 * (w/o treating it as a failure), for example, as in OSE. */
1158 NOREF(aPosition);
1159 NOREF(aFilter);
1160 ReturnComNotImplemented();
1161#endif
1162}
1163
1164STDMETHODIMP Host::RemoveUSBDeviceFilter(ULONG aPosition)
1165{
1166#ifdef VBOX_WITH_USB
1167
1168 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1169 AutoCaller autoCaller(this);
1170 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1171
1172 AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1173
1174 MultiResult rc = checkUSBProxyService();
1175 if (FAILED(rc)) return rc;
1176
1177 if (!m->llUSBDeviceFilters.size())
1178 return setError(E_INVALIDARG,
1179 tr("The USB device filter list is empty"));
1180
1181 if (aPosition >= m->llUSBDeviceFilters.size())
1182 return setError(E_INVALIDARG,
1183 tr("Invalid position: %lu (must be in range [0, %lu])"),
1184 aPosition, m->llUSBDeviceFilters.size() - 1);
1185
1186 ComObjPtr<HostUSBDeviceFilter> filter;
1187 {
1188 /* iterate to the position... */
1189 USBDeviceFilterList::iterator it = m->llUSBDeviceFilters.begin();
1190 std::advance (it, aPosition);
1191 /* ...get an element from there... */
1192 filter = *it;
1193 /* ...and remove */
1194 filter->mInList = false;
1195 m->llUSBDeviceFilters.erase(it);
1196 }
1197
1198 /* notify the proxy (only when the filter is active) */
1199 if (m->pUSBProxyService->isActive() && filter->getData().mActive)
1200 {
1201 ComAssertRet(filter->getId() != NULL, E_FAIL);
1202 m->pUSBProxyService->removeFilter(filter->getId());
1203 filter->getId() = NULL;
1204 }
1205
1206 /* save the global settings */
1207 alock.release();
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, tr (
1402 "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 alock.release();
1771 return m->pParent->saveSettings();
1772 }
1773
1774 return S_OK;
1775}
1776
1777
1778/**
1779 * Interface for obtaining a copy of the USBDeviceFilterList,
1780 * used by the USBProxyService.
1781 *
1782 * @param aGlobalFilters Where to put the global filter list copy.
1783 * @param aMachines Where to put the machine vector.
1784 */
1785void Host::getUSBFilters(Host::USBDeviceFilterList *aGlobalFilters)
1786{
1787 AutoReadLock alock(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1788
1789 *aGlobalFilters = m->llUSBDeviceFilters;
1790}
1791
1792#endif /* VBOX_WITH_USB */
1793
1794// private methods
1795////////////////////////////////////////////////////////////////////////////////
1796
1797#if defined(RT_OS_SOLARIS) && defined(VBOX_USE_LIBHAL)
1798/* Solaris hosts, loading libhal at runtime */
1799
1800/**
1801 * Helper function to query the hal subsystem for information about DVD drives attached to the
1802 * system.
1803 *
1804 * @returns true if information was successfully obtained, false otherwise
1805 * @retval list drives found will be attached to this list
1806 */
1807bool Host::getDVDInfoFromHal(std::list<ComObjPtr<Medium> > &list)
1808{
1809 bool halSuccess = false;
1810 DBusError dbusError;
1811 if (!gLibHalCheckPresence())
1812 return false;
1813 gDBusErrorInit (&dbusError);
1814 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
1815 if (dbusConnection != 0)
1816 {
1817 LibHalContext *halContext = gLibHalCtxNew();
1818 if (halContext != 0)
1819 {
1820 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
1821 {
1822 if (gLibHalCtxInit(halContext, &dbusError))
1823 {
1824 int numDevices;
1825 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
1826 "storage.drive_type", "cdrom",
1827 &numDevices, &dbusError);
1828 if (halDevices != 0)
1829 {
1830 /* Hal is installed and working, so if no devices are reported, assume
1831 that there are none. */
1832 halSuccess = true;
1833 for (int i = 0; i < numDevices; i++)
1834 {
1835 char *devNode = gLibHalDeviceGetPropertyString(halContext,
1836 halDevices[i], "block.device", &dbusError);
1837#ifdef RT_OS_SOLARIS
1838 /* The CD/DVD ioctls work only for raw device nodes. */
1839 char *tmp = getfullrawname(devNode);
1840 gLibHalFreeString(devNode);
1841 devNode = tmp;
1842#endif
1843
1844 if (devNode != 0)
1845 {
1846// if (validateDevice(devNode, true))
1847// {
1848 Utf8Str description;
1849 char *vendor, *product;
1850 /* We do not check the error here, as this field may
1851 not even exist. */
1852 vendor = gLibHalDeviceGetPropertyString(halContext,
1853 halDevices[i], "info.vendor", 0);
1854 product = gLibHalDeviceGetPropertyString(halContext,
1855 halDevices[i], "info.product", &dbusError);
1856 if ((product != 0 && product[0] != 0))
1857 {
1858 if ((vendor != 0) && (vendor[0] != 0))
1859 {
1860 description = Utf8StrFmt ("%s %s",
1861 vendor, product);
1862 }
1863 else
1864 {
1865 description = product;
1866 }
1867 ComObjPtr<Medium> hostDVDDriveObj;
1868 hostDVDDriveObj.createObject();
1869 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
1870 Bstr(devNode), Bstr(description));
1871 list.push_back (hostDVDDriveObj);
1872 }
1873 else
1874 {
1875 if (product == 0)
1876 {
1877 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
1878 halDevices[i], dbusError.name, dbusError.message));
1879 gDBusErrorFree(&dbusError);
1880 }
1881 ComObjPtr<Medium> hostDVDDriveObj;
1882 hostDVDDriveObj.createObject();
1883 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
1884 Bstr(devNode));
1885 list.push_back (hostDVDDriveObj);
1886 }
1887 if (vendor != 0)
1888 {
1889 gLibHalFreeString(vendor);
1890 }
1891 if (product != 0)
1892 {
1893 gLibHalFreeString(product);
1894 }
1895// }
1896// else
1897// {
1898// LogRel(("Host::COMGETTER(DVDDrives): failed to validate the block device %s as a DVD drive\n"));
1899// }
1900#ifndef RT_OS_SOLARIS
1901 gLibHalFreeString(devNode);
1902#else
1903 free(devNode);
1904#endif
1905 }
1906 else
1907 {
1908 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
1909 halDevices[i], dbusError.name, dbusError.message));
1910 gDBusErrorFree(&dbusError);
1911 }
1912 }
1913 gLibHalFreeStringArray(halDevices);
1914 }
1915 else
1916 {
1917 LogRel(("Host::COMGETTER(DVDDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1918 gDBusErrorFree(&dbusError);
1919 }
1920 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
1921 {
1922 LogRel(("Host::COMGETTER(DVDDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1923 gDBusErrorFree(&dbusError);
1924 }
1925 }
1926 else
1927 {
1928 LogRel(("Host::COMGETTER(DVDDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1929 gDBusErrorFree(&dbusError);
1930 }
1931 gLibHalCtxFree(halContext);
1932 }
1933 else
1934 {
1935 LogRel(("Host::COMGETTER(DVDDrives): failed to set libhal connection to dbus.\n"));
1936 }
1937 }
1938 else
1939 {
1940 LogRel(("Host::COMGETTER(DVDDrives): failed to get a libhal context - out of memory?\n"));
1941 }
1942 gDBusConnectionUnref(dbusConnection);
1943 }
1944 else
1945 {
1946 LogRel(("Host::COMGETTER(DVDDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1947 gDBusErrorFree(&dbusError);
1948 }
1949 return halSuccess;
1950}
1951
1952
1953/**
1954 * Helper function to query the hal subsystem for information about floppy drives attached to the
1955 * system.
1956 *
1957 * @returns true if information was successfully obtained, false otherwise
1958 * @retval list drives found will be attached to this list
1959 */
1960bool Host::getFloppyInfoFromHal(std::list< ComObjPtr<Medium> > &list)
1961{
1962 bool halSuccess = false;
1963 DBusError dbusError;
1964 if (!gLibHalCheckPresence())
1965 return false;
1966 gDBusErrorInit (&dbusError);
1967 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
1968 if (dbusConnection != 0)
1969 {
1970 LibHalContext *halContext = gLibHalCtxNew();
1971 if (halContext != 0)
1972 {
1973 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
1974 {
1975 if (gLibHalCtxInit(halContext, &dbusError))
1976 {
1977 int numDevices;
1978 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
1979 "storage.drive_type", "floppy",
1980 &numDevices, &dbusError);
1981 if (halDevices != 0)
1982 {
1983 /* Hal is installed and working, so if no devices are reported, assume
1984 that there are none. */
1985 halSuccess = true;
1986 for (int i = 0; i < numDevices; i++)
1987 {
1988 char *driveType = gLibHalDeviceGetPropertyString(halContext,
1989 halDevices[i], "storage.drive_type", 0);
1990 if (driveType != 0)
1991 {
1992 if (strcmp(driveType, "floppy") != 0)
1993 {
1994 gLibHalFreeString(driveType);
1995 continue;
1996 }
1997 gLibHalFreeString(driveType);
1998 }
1999 else
2000 {
2001 /* An error occurred. The attribute "storage.drive_type"
2002 probably didn't exist. */
2003 continue;
2004 }
2005 char *devNode = gLibHalDeviceGetPropertyString(halContext,
2006 halDevices[i], "block.device", &dbusError);
2007 if (devNode != 0)
2008 {
2009// if (validateDevice(devNode, false))
2010// {
2011 Utf8Str description;
2012 char *vendor, *product;
2013 /* We do not check the error here, as this field may
2014 not even exist. */
2015 vendor = gLibHalDeviceGetPropertyString(halContext,
2016 halDevices[i], "info.vendor", 0);
2017 product = gLibHalDeviceGetPropertyString(halContext,
2018 halDevices[i], "info.product", &dbusError);
2019 if ((product != 0) && (product[0] != 0))
2020 {
2021 if ((vendor != 0) && (vendor[0] != 0))
2022 {
2023 description = Utf8StrFmt ("%s %s",
2024 vendor, product);
2025 }
2026 else
2027 {
2028 description = product;
2029 }
2030 ComObjPtr<Medium> hostFloppyDrive;
2031 hostFloppyDrive.createObject();
2032 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
2033 Bstr(devNode), Bstr(description));
2034 list.push_back (hostFloppyDrive);
2035 }
2036 else
2037 {
2038 if (product == 0)
2039 {
2040 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
2041 halDevices[i], dbusError.name, dbusError.message));
2042 gDBusErrorFree(&dbusError);
2043 }
2044 ComObjPtr<Medium> hostFloppyDrive;
2045 hostFloppyDrive.createObject();
2046 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
2047 Bstr(devNode));
2048 list.push_back (hostFloppyDrive);
2049 }
2050 if (vendor != 0)
2051 {
2052 gLibHalFreeString(vendor);
2053 }
2054 if (product != 0)
2055 {
2056 gLibHalFreeString(product);
2057 }
2058// }
2059// else
2060// {
2061// LogRel(("Host::COMGETTER(FloppyDrives): failed to validate the block device %s as a floppy drive\n"));
2062// }
2063 gLibHalFreeString(devNode);
2064 }
2065 else
2066 {
2067 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
2068 halDevices[i], dbusError.name, dbusError.message));
2069 gDBusErrorFree(&dbusError);
2070 }
2071 }
2072 gLibHalFreeStringArray(halDevices);
2073 }
2074 else
2075 {
2076 LogRel(("Host::COMGETTER(FloppyDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2077 gDBusErrorFree(&dbusError);
2078 }
2079 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
2080 {
2081 LogRel(("Host::COMGETTER(FloppyDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2082 gDBusErrorFree(&dbusError);
2083 }
2084 }
2085 else
2086 {
2087 LogRel(("Host::COMGETTER(FloppyDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2088 gDBusErrorFree(&dbusError);
2089 }
2090 gLibHalCtxFree(halContext);
2091 }
2092 else
2093 {
2094 LogRel(("Host::COMGETTER(FloppyDrives): failed to set libhal connection to dbus.\n"));
2095 }
2096 }
2097 else
2098 {
2099 LogRel(("Host::COMGETTER(FloppyDrives): failed to get a libhal context - out of memory?\n"));
2100 }
2101 gDBusConnectionUnref(dbusConnection);
2102 }
2103 else
2104 {
2105 LogRel(("Host::COMGETTER(FloppyDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2106 gDBusErrorFree(&dbusError);
2107 }
2108 return halSuccess;
2109}
2110#endif /* RT_OS_SOLARIS and VBOX_USE_HAL */
2111
2112/** @todo get rid of dead code below - RT_OS_SOLARIS and RT_OS_LINUX are never both set */
2113#if defined(RT_OS_SOLARIS)
2114
2115/**
2116 * Helper function to parse the given mount file and add found entries
2117 */
2118void Host::parseMountTable(char *mountTable, std::list< ComObjPtr<Medium> > &list)
2119{
2120#ifdef RT_OS_LINUX
2121 FILE *mtab = setmntent(mountTable, "r");
2122 if (mtab)
2123 {
2124 struct mntent *mntent;
2125 char *mnt_type;
2126 char *mnt_dev;
2127 char *tmp;
2128 while ((mntent = getmntent(mtab)))
2129 {
2130 mnt_type = (char*)malloc(strlen(mntent->mnt_type) + 1);
2131 mnt_dev = (char*)malloc(strlen(mntent->mnt_fsname) + 1);
2132 strcpy(mnt_type, mntent->mnt_type);
2133 strcpy(mnt_dev, mntent->mnt_fsname);
2134 // supermount fs case
2135 if (strcmp(mnt_type, "supermount") == 0)
2136 {
2137 tmp = strstr(mntent->mnt_opts, "fs=");
2138 if (tmp)
2139 {
2140 free(mnt_type);
2141 mnt_type = strdup(tmp + strlen("fs="));
2142 if (mnt_type)
2143 {
2144 tmp = strchr(mnt_type, ',');
2145 if (tmp)
2146 *tmp = '\0';
2147 }
2148 }
2149 tmp = strstr(mntent->mnt_opts, "dev=");
2150 if (tmp)
2151 {
2152 free(mnt_dev);
2153 mnt_dev = strdup(tmp + strlen("dev="));
2154 if (mnt_dev)
2155 {
2156 tmp = strchr(mnt_dev, ',');
2157 if (tmp)
2158 *tmp = '\0';
2159 }
2160 }
2161 }
2162 // use strstr here to cover things fs types like "udf,iso9660"
2163 if (strstr(mnt_type, "iso9660") == 0)
2164 {
2165 /** @todo check whether we've already got the drive in our list! */
2166 if (validateDevice(mnt_dev, true))
2167 {
2168 ComObjPtr<Medium> hostDVDDriveObj;
2169 hostDVDDriveObj.createObject();
2170 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(mnt_dev));
2171 list.push_back (hostDVDDriveObj);
2172 }
2173 }
2174 free(mnt_dev);
2175 free(mnt_type);
2176 }
2177 endmntent(mtab);
2178 }
2179#else // RT_OS_SOLARIS
2180 FILE *mntFile = fopen(mountTable, "r");
2181 if (mntFile)
2182 {
2183 struct mnttab mntTab;
2184 while (getmntent(mntFile, &mntTab) == 0)
2185 {
2186 const char *mountName = mntTab.mnt_special;
2187 const char *mountPoint = mntTab.mnt_mountp;
2188 const char *mountFSType = mntTab.mnt_fstype;
2189 if (mountName && mountPoint && mountFSType)
2190 {
2191 // skip devices we are not interested in
2192 if ((*mountName && mountName[0] == '/') && // skip 'fake' devices (like -hosts, proc, fd, swap)
2193 (*mountFSType && (strncmp(mountFSType, "devfs", 5) != 0 && // skip devfs (i.e. /devices)
2194 strncmp(mountFSType, "dev", 3) != 0 && // skip dev (i.e. /dev)
2195 strncmp(mountFSType, "lofs", 4) != 0))) // skip loop-back file-system (lofs)
2196 {
2197 char *rawDevName = getfullrawname((char *)mountName);
2198 if (validateDevice(rawDevName, true))
2199 {
2200 ComObjPtr<Medium> hostDVDDriveObj;
2201 hostDVDDriveObj.createObject();
2202 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(rawDevName));
2203 list.push_back (hostDVDDriveObj);
2204 }
2205 free(rawDevName);
2206 }
2207 }
2208 }
2209
2210 fclose(mntFile);
2211 }
2212#endif
2213}
2214
2215/**
2216 * Helper function to check whether the given device node is a valid drive
2217 */
2218bool Host::validateDevice(const char *deviceNode, bool isCDROM)
2219{
2220 struct stat statInfo;
2221 bool retValue = false;
2222
2223 // sanity check
2224 if (!deviceNode)
2225 {
2226 return false;
2227 }
2228
2229 // first a simple stat() call
2230 if (stat(deviceNode, &statInfo) < 0)
2231 {
2232 return false;
2233 }
2234 else
2235 {
2236 if (isCDROM)
2237 {
2238 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2239 {
2240 int fileHandle;
2241 // now try to open the device
2242 fileHandle = open(deviceNode, O_RDONLY | O_NONBLOCK, 0);
2243 if (fileHandle >= 0)
2244 {
2245 cdrom_subchnl cdChannelInfo;
2246 cdChannelInfo.cdsc_format = CDROM_MSF;
2247 // this call will finally reveal the whole truth
2248#ifdef RT_OS_LINUX
2249 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2250 (errno == EIO) || (errno == ENOENT) ||
2251 (errno == EINVAL) || (errno == ENOMEDIUM))
2252#else
2253 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2254 (errno == EIO) || (errno == ENOENT) ||
2255 (errno == EINVAL))
2256#endif
2257 {
2258 retValue = true;
2259 }
2260 close(fileHandle);
2261 }
2262 }
2263 } else
2264 {
2265 // floppy case
2266 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2267 {
2268 /// @todo do some more testing, maybe a nice IOCTL!
2269 retValue = true;
2270 }
2271 }
2272 }
2273 return retValue;
2274}
2275#endif // RT_OS_SOLARIS
2276
2277#ifdef VBOX_WITH_USB
2278/**
2279 * Checks for the presense and status of the USB Proxy Service.
2280 * Returns S_OK when the Proxy is present and OK, VBOX_E_HOST_ERROR (as a
2281 * warning) if the proxy service is not available due to the way the host is
2282 * configured (at present, that means that usbfs and hal/DBus are not
2283 * available on a Linux host) or E_FAIL and a corresponding error message
2284 * otherwise. Intended to be used by methods that rely on the Proxy Service
2285 * availability.
2286 *
2287 * @note This method may return a warning result code. It is recommended to use
2288 * MultiError to store the return value.
2289 *
2290 * @note Locks this object for reading.
2291 */
2292HRESULT Host::checkUSBProxyService()
2293{
2294 AutoCaller autoCaller(this);
2295 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2296
2297 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2298
2299 AssertReturn(m->pUSBProxyService, E_FAIL);
2300 if (!m->pUSBProxyService->isActive())
2301 {
2302 /* disable the USB controller completely to avoid assertions if the
2303 * USB proxy service could not start. */
2304
2305 if (m->pUSBProxyService->getLastError() == VERR_FILE_NOT_FOUND)
2306 return setWarning (E_FAIL,
2307 tr ("Could not load the Host USB Proxy Service (%Rrc). "
2308 "The service might not be installed on the host computer"),
2309 m->pUSBProxyService->getLastError());
2310 if (m->pUSBProxyService->getLastError() == VINF_SUCCESS)
2311#ifdef RT_OS_LINUX
2312 return setWarning (VBOX_E_HOST_ERROR,
2313# ifdef VBOX_WITH_DBUS
2314 tr ("The USB Proxy Service could not be started, because neither the USB file system (usbfs) nor the hardware information service (hal) is available")
2315# else
2316 tr ("The USB Proxy Service could not be started, because the USB file system (usbfs) is not available")
2317# endif
2318 );
2319#else /* !RT_OS_LINUX */
2320 return setWarning (E_FAIL,
2321 tr ("The USB Proxy Service has not yet been ported to this host"));
2322#endif /* !RT_OS_LINUX */
2323 return setWarning (E_FAIL,
2324 tr ("Could not load the Host USB Proxy service (%Rrc)"),
2325 m->pUSBProxyService->getLastError());
2326 }
2327
2328 return S_OK;
2329}
2330#endif /* VBOX_WITH_USB */
2331
2332#ifdef VBOX_WITH_RESOURCE_USAGE_API
2333
2334void Host::registerMetrics(PerformanceCollector *aCollector)
2335{
2336 pm::CollectorHAL *hal = aCollector->getHAL();
2337 /* Create sub metrics */
2338 pm::SubMetric *cpuLoadUser = new pm::SubMetric("CPU/Load/User",
2339 "Percentage of processor time spent in user mode.");
2340 pm::SubMetric *cpuLoadKernel = new pm::SubMetric("CPU/Load/Kernel",
2341 "Percentage of processor time spent in kernel mode.");
2342 pm::SubMetric *cpuLoadIdle = new pm::SubMetric("CPU/Load/Idle",
2343 "Percentage of processor time spent idling.");
2344 pm::SubMetric *cpuMhzSM = new pm::SubMetric("CPU/MHz",
2345 "Average of current frequency of all processors.");
2346 pm::SubMetric *ramUsageTotal = new pm::SubMetric("RAM/Usage/Total",
2347 "Total physical memory installed.");
2348 pm::SubMetric *ramUsageUsed = new pm::SubMetric("RAM/Usage/Used",
2349 "Physical memory currently occupied.");
2350 pm::SubMetric *ramUsageFree = new pm::SubMetric("RAM/Usage/Free",
2351 "Physical memory currently available to applications.");
2352 pm::SubMetric *ramVMMUsed = new pm::SubMetric("RAM/VMM/Used",
2353 "Total physical memory used by the hypervisor.");
2354 pm::SubMetric *ramVMMFree = new pm::SubMetric("RAM/VMM/Free",
2355 "Total physical memory free inside the hypervisor.");
2356 pm::SubMetric *ramVMMBallooned = new pm::SubMetric("RAM/VMM/Ballooned",
2357 "Total physical memory ballooned by the hypervisor.");
2358 pm::SubMetric *ramVMMShared = new pm::SubMetric("RAM/VMM/Shared",
2359 "Total physical memory shared between VMs.");
2360
2361
2362 /* Create and register base metrics */
2363 IUnknown *objptr;
2364 ComObjPtr<Host> tmp = this;
2365 tmp.queryInterfaceTo(&objptr);
2366 pm::BaseMetric *cpuLoad = new pm::HostCpuLoadRaw(hal, objptr, cpuLoadUser, cpuLoadKernel,
2367 cpuLoadIdle);
2368 aCollector->registerBaseMetric (cpuLoad);
2369 pm::BaseMetric *cpuMhz = new pm::HostCpuMhz(hal, objptr, cpuMhzSM);
2370 aCollector->registerBaseMetric (cpuMhz);
2371 pm::BaseMetric *ramUsage = new pm::HostRamUsage(hal, objptr, ramUsageTotal, ramUsageUsed,
2372 ramUsageFree, ramVMMUsed, ramVMMFree, ramVMMBallooned, ramVMMShared);
2373 aCollector->registerBaseMetric (ramUsage);
2374
2375 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser, 0));
2376 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
2377 new pm::AggregateAvg()));
2378 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
2379 new pm::AggregateMin()));
2380 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
2381 new pm::AggregateMax()));
2382
2383 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel, 0));
2384 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
2385 new pm::AggregateAvg()));
2386 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
2387 new pm::AggregateMin()));
2388 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
2389 new pm::AggregateMax()));
2390
2391 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle, 0));
2392 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
2393 new pm::AggregateAvg()));
2394 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
2395 new pm::AggregateMin()));
2396 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
2397 new pm::AggregateMax()));
2398
2399 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM, 0));
2400 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
2401 new pm::AggregateAvg()));
2402 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
2403 new pm::AggregateMin()));
2404 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
2405 new pm::AggregateMax()));
2406
2407 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal, 0));
2408 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
2409 new pm::AggregateAvg()));
2410 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
2411 new pm::AggregateMin()));
2412 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
2413 new pm::AggregateMax()));
2414
2415 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed, 0));
2416 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
2417 new pm::AggregateAvg()));
2418 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
2419 new pm::AggregateMin()));
2420 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
2421 new pm::AggregateMax()));
2422
2423 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree, 0));
2424 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
2425 new pm::AggregateAvg()));
2426 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
2427 new pm::AggregateMin()));
2428 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
2429 new pm::AggregateMax()));
2430
2431 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMUsed, 0));
2432 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMUsed,
2433 new pm::AggregateAvg()));
2434 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMUsed,
2435 new pm::AggregateMin()));
2436 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMUsed,
2437 new pm::AggregateMax()));
2438
2439 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMFree, 0));
2440 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMFree,
2441 new pm::AggregateAvg()));
2442 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMFree,
2443 new pm::AggregateMin()));
2444 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMFree,
2445 new pm::AggregateMax()));
2446
2447 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMBallooned, 0));
2448 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMBallooned,
2449 new pm::AggregateAvg()));
2450 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMBallooned,
2451 new pm::AggregateMin()));
2452 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMBallooned,
2453 new pm::AggregateMax()));
2454
2455 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMShared, 0));
2456 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMShared,
2457 new pm::AggregateAvg()));
2458 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMShared,
2459 new pm::AggregateMin()));
2460 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMShared,
2461 new pm::AggregateMax()));
2462}
2463
2464void Host::unregisterMetrics (PerformanceCollector *aCollector)
2465{
2466 aCollector->unregisterMetricsFor(this);
2467 aCollector->unregisterBaseMetricsFor(this);
2468}
2469
2470#endif /* VBOX_WITH_RESOURCE_USAGE_API */
2471
2472/* 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