VirtualBox

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

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

Automated rebranding to Oracle copyright/license strings via filemuncher

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