VirtualBox

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

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

Warnings.

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