VirtualBox

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

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

Main: remove VirtualBoxSupportTranslation template, add translation support to generic base class, clean up COM headers more, remove SupportErrorInfo.cpp|h

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette