VirtualBox

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

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

Main: coding style

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