VirtualBox

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

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

Main/Host: remove host lock from Host::GetNetworkInterfaces (the other methods which enumerate interfaces don't take it either), and leave the VirtualBox lock for the called setVirtualBox method since there is no chance of lock order violations any more

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