VirtualBox

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

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

Main: Bstr makeover (third attempt) -- make Bstr(NULL) and Bstr() behave the same; resulting cleanup; make some more internal methods use Utf8Str instead of Bstr; fix a lot of CheckComArgNotNull??() usage

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 83.7 KB
Line 
1/* $Id: HostImpl.cpp 26753 2010-02-24 16:24:33Z 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 Bstr name((CBSTR)lpszName);
454
455 hr = pncc->GetInstanceGuid(&IfGuid);
456 Assert(hr == S_OK);
457 if (hr == S_OK)
458 {
459 /* create a new object and add it to the list */
460 ComObjPtr<HostNetworkInterface> iface;
461 iface.createObject();
462 /* remove the curly bracket at the end */
463 if (SUCCEEDED(iface->init (name, Guid (IfGuid), HostNetworkInterfaceType_Bridged)))
464 {
465// iface->setVirtualBox(m->pParent);
466 pPist->push_back(iface);
467 rc = VINF_SUCCESS;
468 }
469 else
470 {
471 Assert(0);
472 }
473 }
474 CoTaskMemFree(lpszName);
475 }
476
477 return rc;
478}
479#endif /* defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT) */
480
481/**
482 * Returns a list of host network interfaces.
483 *
484 * @returns COM status code
485 * @param drives address of result pointer
486 */
487STDMETHODIMP Host::COMGETTER(NetworkInterfaces)(ComSafeArrayOut(IHostNetworkInterface*, aNetworkInterfaces))
488{
489#if defined(RT_OS_WINDOWS) || defined(VBOX_WITH_NETFLT) /*|| defined(RT_OS_OS2)*/
490 if (ComSafeArrayOutIsNull(aNetworkInterfaces))
491 return E_POINTER;
492
493 AutoCaller autoCaller(this);
494 if (FAILED(autoCaller.rc())) return autoCaller.rc();
495
496 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
497
498 std::list <ComObjPtr<HostNetworkInterface> > list;
499
500# ifdef VBOX_WITH_HOSTNETIF_API
501 int rc = NetIfList(list);
502 if (rc)
503 {
504 Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
505 }
506# else
507
508# if defined(RT_OS_DARWIN)
509 PDARWINETHERNIC pEtherNICs = DarwinGetEthernetControllers();
510 while (pEtherNICs)
511 {
512 ComObjPtr<HostNetworkInterface> IfObj;
513 IfObj.createObject();
514 if (SUCCEEDED(IfObj->init(Bstr(pEtherNICs->szName), Guid(pEtherNICs->Uuid), HostNetworkInterfaceType_Bridged)))
515 list.push_back(IfObj);
516
517 /* next, free current */
518 void *pvFree = pEtherNICs;
519 pEtherNICs = pEtherNICs->pNext;
520 RTMemFree(pvFree);
521 }
522
523# elif defined(RT_OS_SOLARIS)
524
525# ifdef VBOX_SOLARIS_NSL_RESOLVED
526
527 /*
528 * Use libdevinfo for determining all physical interfaces.
529 */
530 di_node_t Root;
531 Root = di_init("/", DINFOCACHE);
532 if (Root != DI_NODE_NIL)
533 {
534 di_walk_minor(Root, DDI_NT_NET, 0, &list, vboxSolarisAddPhysHostIface);
535 di_fini(Root);
536 }
537
538 /*
539 * Use libdlpi for determining all DLPI interfaces.
540 */
541 if (VBoxSolarisLibDlpiFound())
542 g_pfnLibDlpiWalk(vboxSolarisAddLinkHostIface, &list, 0);
543
544# endif /* VBOX_SOLARIS_NSL_RESOLVED */
545
546 /*
547 * This gets only the list of all plumbed logical interfaces.
548 * This is needed for zones which cannot access the device tree
549 * and in this case we just let them use the list of plumbed interfaces
550 * on the zone.
551 */
552 int Sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
553 if (Sock > 0)
554 {
555 struct lifnum IfNum;
556 memset(&IfNum, 0, sizeof(IfNum));
557 IfNum.lifn_family = AF_INET;
558 int rc = ioctl(Sock, SIOCGLIFNUM, &IfNum);
559 if (!rc)
560 {
561 struct lifreq Ifaces[24];
562 struct lifconf IfConfig;
563 memset(&IfConfig, 0, sizeof(IfConfig));
564 IfConfig.lifc_family = AF_INET;
565 IfConfig.lifc_len = sizeof(Ifaces);
566 IfConfig.lifc_buf = (caddr_t)&(Ifaces[0]);
567 rc = ioctl(Sock, SIOCGLIFCONF, &IfConfig);
568 if (!rc)
569 {
570 for (int i = 0; i < IfNum.lifn_count; i++)
571 {
572 /*
573 * Skip loopback interfaces.
574 */
575 if (!strncmp(Ifaces[i].lifr_name, "lo", 2))
576 continue;
577
578#if 0
579 rc = ioctl(Sock, SIOCGLIFADDR, &(Ifaces[i]));
580 if (!rc)
581 {
582 RTMAC Mac;
583 struct arpreq ArpReq;
584 memcpy(&ArpReq.arp_pa, &Ifaces[i].lifr_addr, sizeof(struct sockaddr_in));
585
586 /*
587 * We might fail if the interface has not been assigned an IP address.
588 * That doesn't matter; as long as it's plumbed we can pick it up.
589 * But, if it has not acquired an IP address we cannot obtain it's MAC
590 * address this way, so we just use all zeros there.
591 */
592 rc = ioctl(Sock, SIOCGARP, &ArpReq);
593 if (!rc)
594 memcpy(&Mac, ArpReq.arp_ha.sa_data, sizeof(RTMAC));
595 else
596 memset(&Mac, 0, sizeof(Mac));
597
598 char szNICDesc[LIFNAMSIZ + 256];
599 char *pszIface = Ifaces[i].lifr_name;
600 strcpy(szNICDesc, pszIface);
601
602 vboxSolarisAddLinkHostIface(pszIface, &list);
603 }
604#endif
605
606 char *pszIface = Ifaces[i].lifr_name;
607 vboxSolarisAddLinkHostIface(pszIface, &list);
608 }
609 }
610 }
611 close(Sock);
612 }
613
614 /*
615 * Weed out duplicates caused by dlpi_walk inconsistencies across Nevadas.
616 */
617 list.sort(vboxSolarisSortNICList);
618 list.unique(vboxSolarisSameNIC);
619
620# elif defined RT_OS_WINDOWS
621# ifndef VBOX_WITH_NETFLT
622 hr = E_NOTIMPL;
623# else /* # if defined VBOX_WITH_NETFLT */
624 INetCfg *pNc;
625 INetCfgComponent *pMpNcc;
626 INetCfgComponent *pTcpIpNcc;
627 LPWSTR lpszApp;
628 HRESULT hr;
629 IEnumNetCfgBindingPath *pEnumBp;
630 INetCfgBindingPath *pBp;
631 IEnumNetCfgBindingInterface *pEnumBi;
632 INetCfgBindingInterface *pBi;
633
634 /* we are using the INetCfg API for getting the list of miniports */
635 hr = VBoxNetCfgWinQueryINetCfg( FALSE,
636 VBOX_APP_NAME,
637 &pNc,
638 &lpszApp );
639 Assert(hr == S_OK);
640 if(hr == S_OK)
641 {
642# ifdef VBOX_NETFLT_ONDEMAND_BIND
643 /* for the protocol-based approach for now we just get all miniports the MS_TCPIP protocol binds to */
644 hr = pNc->FindComponent(L"MS_TCPIP", &pTcpIpNcc);
645# else
646 /* for the filter-based approach we get all miniports our filter (sun_VBoxNetFlt)is bound to */
647 hr = pNc->FindComponent(L"sun_VBoxNetFlt", &pTcpIpNcc);
648# ifndef VBOX_WITH_HARDENING
649 if(hr != S_OK)
650 {
651 /* TODO: try to install the netflt from here */
652 }
653# endif
654
655# endif
656
657 if(hr == S_OK)
658 {
659 hr = VBoxNetCfgWinGetBindingPathEnum(pTcpIpNcc, EBP_BELOW, &pEnumBp);
660 Assert(hr == S_OK);
661 if ( hr == S_OK )
662 {
663 hr = VBoxNetCfgWinGetFirstBindingPath(pEnumBp, &pBp);
664 Assert(hr == S_OK || hr == S_FALSE);
665 while( hr == S_OK )
666 {
667 /* S_OK == enabled, S_FALSE == disabled */
668 if(pBp->IsEnabled() == S_OK)
669 {
670 hr = VBoxNetCfgWinGetBindingInterfaceEnum(pBp, &pEnumBi);
671 Assert(hr == S_OK);
672 if ( hr == S_OK )
673 {
674 hr = VBoxNetCfgWinGetFirstBindingInterface(pEnumBi, &pBi);
675 Assert(hr == S_OK);
676 while(hr == S_OK)
677 {
678 hr = pBi->GetLowerComponent( &pMpNcc );
679 Assert(hr == S_OK);
680 if(hr == S_OK)
681 {
682 ULONG uComponentStatus;
683 hr = pMpNcc->GetDeviceStatus(&uComponentStatus);
684 Assert(hr == S_OK);
685 if(hr == S_OK)
686 {
687 if(uComponentStatus == 0)
688 {
689 vboxNetWinAddComponent(&list, pMpNcc);
690 }
691 }
692 VBoxNetCfgWinReleaseRef( pMpNcc );
693 }
694 VBoxNetCfgWinReleaseRef(pBi);
695
696 hr = VBoxNetCfgWinGetNextBindingInterface(pEnumBi, &pBi);
697 }
698 VBoxNetCfgWinReleaseRef(pEnumBi);
699 }
700 }
701 VBoxNetCfgWinReleaseRef(pBp);
702
703 hr = VBoxNetCfgWinGetNextBindingPath(pEnumBp, &pBp);
704 }
705 VBoxNetCfgWinReleaseRef(pEnumBp);
706 }
707 VBoxNetCfgWinReleaseRef(pTcpIpNcc);
708 }
709 else
710 {
711 LogRel(("failed to get the sun_VBoxNetFlt component, error (0x%x)", hr));
712 }
713
714 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE);
715 }
716# endif /* # if defined VBOX_WITH_NETFLT */
717
718
719# elif defined RT_OS_LINUX
720 int sock = socket(AF_INET, SOCK_DGRAM, 0);
721 if (sock >= 0)
722 {
723 char pBuffer[2048];
724 struct ifconf ifConf;
725 ifConf.ifc_len = sizeof(pBuffer);
726 ifConf.ifc_buf = pBuffer;
727 if (ioctl(sock, SIOCGIFCONF, &ifConf) >= 0)
728 {
729 for (struct ifreq *pReq = ifConf.ifc_req; (char*)pReq < pBuffer + ifConf.ifc_len; pReq++)
730 {
731 if (ioctl(sock, SIOCGIFHWADDR, pReq) >= 0)
732 {
733 if (pReq->ifr_hwaddr.sa_family == ARPHRD_ETHER)
734 {
735 RTUUID uuid;
736 Assert(sizeof(uuid) <= sizeof(*pReq));
737 memcpy(&uuid, pReq, sizeof(uuid));
738
739 ComObjPtr<HostNetworkInterface> IfObj;
740 IfObj.createObject();
741 if (SUCCEEDED(IfObj->init(Bstr(pReq->ifr_name), Guid(uuid), HostNetworkInterfaceType_Bridged)))
742 list.push_back(IfObj);
743 }
744 }
745 }
746 }
747 close(sock);
748 }
749# endif /* RT_OS_LINUX */
750# endif
751
752 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
753 for (it = list.begin(); it != list.end(); ++it)
754 {
755 (*it)->setVirtualBox(m->pParent);
756 }
757
758 SafeIfaceArray<IHostNetworkInterface> networkInterfaces (list);
759 networkInterfaces.detachTo(ComSafeArrayOutArg(aNetworkInterfaces));
760
761 return S_OK;
762
763#else
764 /* Not implemented / supported on this platform. */
765 ReturnComNotImplemented();
766#endif
767}
768
769STDMETHODIMP Host::COMGETTER(USBDevices)(ComSafeArrayOut(IHostUSBDevice*, aUSBDevices))
770{
771#ifdef VBOX_WITH_USB
772 CheckComArgOutSafeArrayPointerValid(aUSBDevices);
773
774 AutoCaller autoCaller(this);
775 if (FAILED(autoCaller.rc())) return autoCaller.rc();
776
777 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
778
779 MultiResult rc = checkUSBProxyService();
780 if (FAILED(rc)) return rc;
781
782 return m->pUSBProxyService->getDeviceCollection(ComSafeArrayOutArg(aUSBDevices));
783
784#else
785 /* Note: The GUI depends on this method returning E_NOTIMPL with no
786 * extended error info to indicate that USB is simply not available
787 * (w/o treating it as a failure), for example, as in OSE. */
788 NOREF(aUSBDevices);
789# ifndef RT_OS_WINDOWS
790 NOREF(aUSBDevicesSize);
791# endif
792 ReturnComNotImplemented();
793#endif
794}
795
796STDMETHODIMP Host::COMGETTER(USBDeviceFilters)(ComSafeArrayOut(IHostUSBDeviceFilter*, aUSBDeviceFilters))
797{
798#ifdef VBOX_WITH_USB
799 CheckComArgOutSafeArrayPointerValid(aUSBDeviceFilters);
800
801 AutoCaller autoCaller(this);
802 if (FAILED(autoCaller.rc())) return autoCaller.rc();
803
804 AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
805
806 MultiResult rc = checkUSBProxyService();
807 if (FAILED(rc)) return rc;
808
809 SafeIfaceArray<IHostUSBDeviceFilter> collection(m->llUSBDeviceFilters);
810 collection.detachTo(ComSafeArrayOutArg(aUSBDeviceFilters));
811
812 return rc;
813#else
814 /* Note: The GUI depends on this method returning E_NOTIMPL with no
815 * extended error info to indicate that USB is simply not available
816 * (w/o treating it as a failure), for example, as in OSE. */
817 NOREF(aUSBDeviceFilters);
818# ifndef RT_OS_WINDOWS
819 NOREF(aUSBDeviceFiltersSize);
820# endif
821 ReturnComNotImplemented();
822#endif
823}
824
825/**
826 * Returns the number of installed logical processors
827 *
828 * @returns COM status code
829 * @param count address of result variable
830 */
831STDMETHODIMP Host::COMGETTER(ProcessorCount)(ULONG *aCount)
832{
833 CheckComArgOutPointerValid(aCount);
834 // no locking required
835
836 *aCount = RTMpGetPresentCount();
837 return S_OK;
838}
839
840/**
841 * Returns the number of online logical processors
842 *
843 * @returns COM status code
844 * @param count address of result variable
845 */
846STDMETHODIMP Host::COMGETTER(ProcessorOnlineCount)(ULONG *aCount)
847{
848 CheckComArgOutPointerValid(aCount);
849 // no locking required
850
851 *aCount = RTMpGetOnlineCount();
852 return S_OK;
853}
854
855/**
856 * Returns the (approximate) maximum speed of the given host CPU in MHz
857 *
858 * @returns COM status code
859 * @param cpu id to get info for.
860 * @param speed address of result variable, speed is 0 if unknown or aCpuId is invalid.
861 */
862STDMETHODIMP Host::GetProcessorSpeed(ULONG aCpuId, ULONG *aSpeed)
863{
864 CheckComArgOutPointerValid(aSpeed);
865 // no locking required
866
867 *aSpeed = RTMpGetMaxFrequency(aCpuId);
868 return S_OK;
869}
870
871/**
872 * Returns a description string for the host CPU
873 *
874 * @returns COM status code
875 * @param cpu id to get info for.
876 * @param description address of result variable, empty string if not known or aCpuId is invalid.
877 */
878STDMETHODIMP Host::GetProcessorDescription(ULONG aCpuId, BSTR *aDescription)
879{
880 CheckComArgOutPointerValid(aDescription);
881 // no locking required
882
883 char szCPUModel[80];
884 int vrc = RTMpGetDescription(aCpuId, szCPUModel, sizeof(szCPUModel));
885 if (RT_FAILURE(vrc))
886 return E_FAIL; /** @todo error reporting? */
887 Bstr (szCPUModel).cloneTo(aDescription);
888 return S_OK;
889}
890
891/**
892 * Returns whether a host processor feature is supported or not
893 *
894 * @returns COM status code
895 * @param Feature to query.
896 * @param address of supported bool result variable
897 */
898STDMETHODIMP Host::GetProcessorFeature(ProcessorFeature_T aFeature, BOOL *aSupported)
899{
900 CheckComArgOutPointerValid(aSupported);
901 AutoCaller autoCaller(this);
902 if (FAILED(autoCaller.rc())) return autoCaller.rc();
903
904 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
905
906 switch (aFeature)
907 {
908 case ProcessorFeature_HWVirtEx:
909 *aSupported = m->fVTSupported;
910 break;
911
912 case ProcessorFeature_PAE:
913 *aSupported = m->fPAESupported;
914 break;
915
916 case ProcessorFeature_LongMode:
917 *aSupported = m->fLongModeSupported;
918 break;
919
920 case ProcessorFeature_NestedPaging:
921 *aSupported = m->fNestedPagingSupported;
922 break;
923
924 default:
925 ReturnComNotImplemented();
926 }
927 return S_OK;
928}
929
930/**
931 * Returns the specific CPUID leaf.
932 *
933 * @returns COM status code
934 * @param aCpuId The CPU number. Mostly ignored.
935 * @param aLeaf The leaf number.
936 * @param aSubLeaf The sub-leaf number.
937 * @param aValEAX Where to return EAX.
938 * @param aValEBX Where to return EBX.
939 * @param aValECX Where to return ECX.
940 * @param aValEDX Where to return EDX.
941 */
942STDMETHODIMP Host::GetProcessorCpuIdLeaf(ULONG aCpuId, ULONG aLeaf, ULONG aSubLeaf,
943 ULONG *aValEAX, ULONG *aValEBX, ULONG *aValECX, ULONG *aValEDX)
944{
945 CheckComArgOutPointerValid(aValEAX);
946 CheckComArgOutPointerValid(aValEBX);
947 CheckComArgOutPointerValid(aValECX);
948 CheckComArgOutPointerValid(aValEDX);
949 // no locking required
950
951 /* Check that the CPU is online. */
952 /** @todo later use RTMpOnSpecific. */
953 if (!RTMpIsCpuOnline(aCpuId))
954 return RTMpIsCpuPresent(aCpuId)
955 ? setError(E_FAIL, tr("CPU no.%u is not present"), aCpuId)
956 : setError(E_FAIL, tr("CPU no.%u is not online"), aCpuId);
957
958 uint32_t uEAX, uEBX, uECX, uEDX;
959 ASMCpuId_Idx_ECX(aLeaf, aSubLeaf, &uEAX, &uEBX, &uECX, &uEDX);
960 *aValEAX = uEAX;
961 *aValEBX = uEBX;
962 *aValECX = uECX;
963 *aValEDX = uEDX;
964
965 return S_OK;
966}
967
968/**
969 * Returns the amount of installed system memory in megabytes
970 *
971 * @returns COM status code
972 * @param size address of result variable
973 */
974STDMETHODIMP Host::COMGETTER(MemorySize)(ULONG *aSize)
975{
976 CheckComArgOutPointerValid(aSize);
977 // no locking required
978
979 /* @todo This is an ugly hack. There must be a function in IPRT for that. */
980 pm::CollectorHAL *hal = pm::createHAL();
981 if (!hal)
982 return E_FAIL;
983 ULONG tmp;
984 int rc = hal->getHostMemoryUsage(aSize, &tmp, &tmp);
985 *aSize /= 1024;
986 delete hal;
987 return rc;
988}
989
990/**
991 * Returns the current system memory free space in megabytes
992 *
993 * @returns COM status code
994 * @param available address of result variable
995 */
996STDMETHODIMP Host::COMGETTER(MemoryAvailable)(ULONG *aAvailable)
997{
998 CheckComArgOutPointerValid(aAvailable);
999 // no locking required
1000
1001 /* @todo This is an ugly hack. There must be a function in IPRT for that. */
1002 pm::CollectorHAL *hal = pm::createHAL();
1003 if (!hal)
1004 return E_FAIL;
1005 ULONG tmp;
1006 int rc = hal->getHostMemoryUsage(&tmp, &tmp, aAvailable);
1007 *aAvailable /= 1024;
1008 delete hal;
1009 return rc;
1010}
1011
1012/**
1013 * Returns the name string of the host operating system
1014 *
1015 * @returns COM status code
1016 * @param os address of result variable
1017 */
1018STDMETHODIMP Host::COMGETTER(OperatingSystem)(BSTR *aOs)
1019{
1020 CheckComArgOutPointerValid(aOs);
1021 // no locking required
1022
1023 char szOSName[80];
1024 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szOSName, sizeof(szOSName));
1025 if (RT_FAILURE(vrc))
1026 return E_FAIL; /** @todo error reporting? */
1027 Bstr (szOSName).cloneTo(aOs);
1028 return S_OK;
1029}
1030
1031/**
1032 * Returns the version string of the host operating system
1033 *
1034 * @returns COM status code
1035 * @param os address of result variable
1036 */
1037STDMETHODIMP Host::COMGETTER(OSVersion)(BSTR *aVersion)
1038{
1039 CheckComArgOutPointerValid(aVersion);
1040 // no locking required
1041
1042 /* Get the OS release. Reserve some buffer space for the service pack. */
1043 char szOSRelease[128];
1044 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOSRelease, sizeof(szOSRelease) - 32);
1045 if (RT_FAILURE(vrc))
1046 return E_FAIL; /** @todo error reporting? */
1047
1048 /* Append the service pack if present. */
1049 char szOSServicePack[80];
1050 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szOSServicePack, sizeof(szOSServicePack));
1051 if (RT_FAILURE(vrc))
1052 {
1053 if (vrc != VERR_NOT_SUPPORTED)
1054 return E_FAIL; /** @todo error reporting? */
1055 szOSServicePack[0] = '\0';
1056 }
1057 if (szOSServicePack[0] != '\0')
1058 {
1059 char *psz = strchr(szOSRelease, '\0');
1060 RTStrPrintf(psz, &szOSRelease[sizeof(szOSRelease)] - psz, "sp%s", szOSServicePack);
1061 }
1062
1063 Bstr(szOSRelease).cloneTo(aVersion);
1064 return S_OK;
1065}
1066
1067/**
1068 * Returns the current host time in milliseconds since 1970-01-01 UTC.
1069 *
1070 * @returns COM status code
1071 * @param time address of result variable
1072 */
1073STDMETHODIMP Host::COMGETTER(UTCTime)(LONG64 *aUTCTime)
1074{
1075 CheckComArgOutPointerValid(aUTCTime);
1076 // no locking required
1077
1078 RTTIMESPEC now;
1079 *aUTCTime = RTTimeSpecGetMilli(RTTimeNow(&now));
1080
1081 return S_OK;
1082}
1083
1084STDMETHODIMP Host::COMGETTER(Acceleration3DAvailable)(BOOL *aSupported)
1085{
1086 CheckComArgOutPointerValid(aSupported);
1087 AutoCaller autoCaller(this);
1088 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1089
1090 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1091
1092 *aSupported = m->f3DAccelerationSupported;
1093
1094 return S_OK;
1095}
1096
1097STDMETHODIMP Host::CreateHostOnlyNetworkInterface(IHostNetworkInterface **aHostNetworkInterface,
1098 IProgress **aProgress)
1099{
1100 CheckComArgOutPointerValid(aHostNetworkInterface);
1101 CheckComArgOutPointerValid(aProgress);
1102
1103 AutoCaller autoCaller(this);
1104 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1105
1106 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1107
1108 int r = NetIfCreateHostOnlyNetworkInterface(m->pParent, aHostNetworkInterface, aProgress);
1109 if (RT_SUCCESS(r))
1110 return S_OK;
1111
1112 return r == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
1113}
1114
1115STDMETHODIMP Host::RemoveHostOnlyNetworkInterface(IN_BSTR aId,
1116 IProgress **aProgress)
1117{
1118 CheckComArgOutPointerValid(aProgress);
1119
1120 AutoCaller autoCaller(this);
1121 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1122
1123 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1124
1125 /* first check whether an interface with the given name already exists */
1126 {
1127 ComPtr<IHostNetworkInterface> iface;
1128 if (FAILED(FindHostNetworkInterfaceById(aId,
1129 iface.asOutParam())))
1130 return setError(VBOX_E_OBJECT_NOT_FOUND,
1131 tr("Host network interface with UUID {%RTuuid} does not exist"),
1132 Guid (aId).raw());
1133 }
1134
1135 int r = NetIfRemoveHostOnlyNetworkInterface(m->pParent, Guid(aId), aProgress);
1136 if (RT_SUCCESS(r))
1137 return S_OK;
1138
1139 return r == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
1140}
1141
1142STDMETHODIMP Host::CreateUSBDeviceFilter(IN_BSTR aName,
1143 IHostUSBDeviceFilter **aFilter)
1144{
1145#ifdef VBOX_WITH_USB
1146 CheckComArgStrNotEmptyOrNull(aName);
1147 CheckComArgOutPointerValid(aFilter);
1148
1149 AutoCaller autoCaller(this);
1150 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1151
1152 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1153
1154 ComObjPtr<HostUSBDeviceFilter> filter;
1155 filter.createObject();
1156 HRESULT rc = filter->init(this, aName);
1157 ComAssertComRCRet(rc, rc);
1158 rc = filter.queryInterfaceTo(aFilter);
1159 AssertComRCReturn(rc, rc);
1160 return S_OK;
1161#else
1162 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1163 * extended error info to indicate that USB is simply not available
1164 * (w/o treating it as a failure), for example, as in OSE. */
1165 NOREF(aName);
1166 NOREF(aFilter);
1167 ReturnComNotImplemented();
1168#endif
1169}
1170
1171STDMETHODIMP Host::InsertUSBDeviceFilter(ULONG aPosition,
1172 IHostUSBDeviceFilter *aFilter)
1173{
1174#ifdef VBOX_WITH_USB
1175 CheckComArgNotNull(aFilter);
1176
1177 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1178 AutoCaller autoCaller(this);
1179 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1180
1181 AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1182
1183 MultiResult rc = checkUSBProxyService();
1184 if (FAILED(rc)) return rc;
1185
1186 ComObjPtr<HostUSBDeviceFilter> pFilter;
1187 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
1188 it != m->llChildren.end();
1189 ++it)
1190 {
1191 if (*it == aFilter)
1192 {
1193 pFilter = *it;
1194 break;
1195 }
1196 }
1197 if (pFilter.isNull())
1198 return setError(VBOX_E_INVALID_OBJECT_STATE,
1199 tr("The given USB device filter is not created within this VirtualBox instance"));
1200
1201 if (pFilter->mInList)
1202 return setError(E_INVALIDARG,
1203 tr("The given USB device filter is already in the list"));
1204
1205 /* iterate to the position... */
1206 USBDeviceFilterList::iterator it = m->llUSBDeviceFilters.begin();
1207 std::advance (it, aPosition);
1208 /* ...and insert */
1209 m->llUSBDeviceFilters.insert(it, pFilter);
1210 pFilter->mInList = true;
1211
1212 /* notify the proxy (only when the filter is active) */
1213 if ( m->pUSBProxyService->isActive()
1214 && pFilter->getData().mActive)
1215 {
1216 ComAssertRet(pFilter->getId() == NULL, E_FAIL);
1217 pFilter->getId() = m->pUSBProxyService->insertFilter(&pFilter->getData().mUSBFilter);
1218 }
1219
1220 /* save the global settings */
1221 alock.release();
1222 return rc = m->pParent->saveSettings();
1223#else
1224 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1225 * extended error info to indicate that USB is simply not available
1226 * (w/o treating it as a failure), for example, as in OSE. */
1227 NOREF(aPosition);
1228 NOREF(aFilter);
1229 ReturnComNotImplemented();
1230#endif
1231}
1232
1233STDMETHODIMP Host::RemoveUSBDeviceFilter(ULONG aPosition)
1234{
1235#ifdef VBOX_WITH_USB
1236
1237 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1238 AutoCaller autoCaller(this);
1239 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1240
1241 AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1242
1243 MultiResult rc = checkUSBProxyService();
1244 if (FAILED(rc)) return rc;
1245
1246 if (!m->llUSBDeviceFilters.size())
1247 return setError(E_INVALIDARG,
1248 tr("The USB device filter list is empty"));
1249
1250 if (aPosition >= m->llUSBDeviceFilters.size())
1251 return setError(E_INVALIDARG,
1252 tr("Invalid position: %lu (must be in range [0, %lu])"),
1253 aPosition, m->llUSBDeviceFilters.size() - 1);
1254
1255 ComObjPtr<HostUSBDeviceFilter> filter;
1256 {
1257 /* iterate to the position... */
1258 USBDeviceFilterList::iterator it = m->llUSBDeviceFilters.begin();
1259 std::advance (it, aPosition);
1260 /* ...get an element from there... */
1261 filter = *it;
1262 /* ...and remove */
1263 filter->mInList = false;
1264 m->llUSBDeviceFilters.erase(it);
1265 }
1266
1267 /* notify the proxy (only when the filter is active) */
1268 if (m->pUSBProxyService->isActive() && filter->getData().mActive)
1269 {
1270 ComAssertRet(filter->getId() != NULL, E_FAIL);
1271 m->pUSBProxyService->removeFilter(filter->getId());
1272 filter->getId() = NULL;
1273 }
1274
1275 /* save the global settings */
1276 alock.release();
1277 return rc = m->pParent->saveSettings();
1278#else
1279 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1280 * extended error info to indicate that USB is simply not available
1281 * (w/o treating it as a failure), for example, as in OSE. */
1282 NOREF(aPosition);
1283 ReturnComNotImplemented();
1284#endif
1285}
1286
1287STDMETHODIMP Host::FindHostDVDDrive(IN_BSTR aName, IMedium **aDrive)
1288{
1289 CheckComArgStrNotEmptyOrNull(aName);
1290 CheckComArgOutPointerValid(aDrive);
1291
1292 *aDrive = NULL;
1293
1294 SafeIfaceArray<IMedium> drivevec;
1295 HRESULT rc = COMGETTER(DVDDrives)(ComSafeArrayAsOutParam(drivevec));
1296 if (FAILED(rc)) return rc;
1297
1298 for (size_t i = 0; i < drivevec.size(); ++i)
1299 {
1300 ComPtr<IMedium> drive = drivevec[i];
1301 Bstr name, location;
1302 rc = drive->COMGETTER(Name)(name.asOutParam());
1303 if (FAILED(rc)) return rc;
1304 rc = drive->COMGETTER(Location)(location.asOutParam());
1305 if (FAILED(rc)) return rc;
1306 if (name == aName || location == aName)
1307 return drive.queryInterfaceTo(aDrive);
1308 }
1309
1310 return setError(VBOX_E_OBJECT_NOT_FOUND,
1311 Medium::tr("The host DVD drive named '%ls' could not be found"), aName);
1312}
1313
1314STDMETHODIMP Host::FindHostFloppyDrive(IN_BSTR aName, IMedium **aDrive)
1315{
1316 CheckComArgStrNotEmptyOrNull(aName);
1317 CheckComArgOutPointerValid(aDrive);
1318
1319 *aDrive = NULL;
1320
1321 SafeIfaceArray<IMedium> drivevec;
1322 HRESULT rc = COMGETTER(FloppyDrives)(ComSafeArrayAsOutParam(drivevec));
1323 if (FAILED(rc)) return rc;
1324
1325 for (size_t i = 0; i < drivevec.size(); ++i)
1326 {
1327 ComPtr<IMedium> drive = drivevec[i];
1328 Bstr name;
1329 rc = drive->COMGETTER(Name)(name.asOutParam());
1330 if (FAILED(rc)) return rc;
1331 if (name == aName)
1332 return drive.queryInterfaceTo(aDrive);
1333 }
1334
1335 return setError(VBOX_E_OBJECT_NOT_FOUND,
1336 Medium::tr("The host floppy drive named '%ls' could not be found"), aName);
1337}
1338
1339STDMETHODIMP Host::FindHostNetworkInterfaceByName(IN_BSTR name, IHostNetworkInterface **networkInterface)
1340{
1341#ifndef VBOX_WITH_HOSTNETIF_API
1342 return E_NOTIMPL;
1343#else
1344 if (!name)
1345 return E_INVALIDARG;
1346 if (!networkInterface)
1347 return E_POINTER;
1348
1349 *networkInterface = NULL;
1350 ComObjPtr<HostNetworkInterface> found;
1351 std::list <ComObjPtr<HostNetworkInterface> > list;
1352 int rc = NetIfList(list);
1353 if (RT_FAILURE(rc))
1354 {
1355 Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
1356 return E_FAIL;
1357 }
1358 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
1359 for (it = list.begin(); it != list.end(); ++it)
1360 {
1361 Bstr n;
1362 (*it)->COMGETTER(Name) (n.asOutParam());
1363 if (n == name)
1364 found = *it;
1365 }
1366
1367 if (!found)
1368 return setError(E_INVALIDARG,
1369 HostNetworkInterface::tr("The host network interface with the given name could not be found"));
1370
1371 found->setVirtualBox(m->pParent);
1372
1373 return found.queryInterfaceTo(networkInterface);
1374#endif
1375}
1376
1377STDMETHODIMP Host::FindHostNetworkInterfaceById(IN_BSTR id, IHostNetworkInterface **networkInterface)
1378{
1379#ifndef VBOX_WITH_HOSTNETIF_API
1380 return E_NOTIMPL;
1381#else
1382 if (Guid(id).isEmpty())
1383 return E_INVALIDARG;
1384 if (!networkInterface)
1385 return E_POINTER;
1386
1387 *networkInterface = NULL;
1388 ComObjPtr<HostNetworkInterface> found;
1389 std::list <ComObjPtr<HostNetworkInterface> > list;
1390 int rc = NetIfList(list);
1391 if (RT_FAILURE(rc))
1392 {
1393 Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
1394 return E_FAIL;
1395 }
1396 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
1397 for (it = list.begin(); it != list.end(); ++it)
1398 {
1399 Bstr g;
1400 (*it)->COMGETTER(Id) (g.asOutParam());
1401 if (g == id)
1402 found = *it;
1403 }
1404
1405 if (!found)
1406 return setError(E_INVALIDARG,
1407 HostNetworkInterface::tr("The host network interface with the given GUID could not be found"));
1408
1409 found->setVirtualBox(m->pParent);
1410
1411 return found.queryInterfaceTo(networkInterface);
1412#endif
1413}
1414
1415STDMETHODIMP Host::FindHostNetworkInterfacesOfType(HostNetworkInterfaceType_T type,
1416 ComSafeArrayOut(IHostNetworkInterface *, aNetworkInterfaces))
1417{
1418 std::list <ComObjPtr<HostNetworkInterface> > allList;
1419 int rc = NetIfList(allList);
1420 if(RT_FAILURE(rc))
1421 return E_FAIL;
1422
1423 std::list <ComObjPtr<HostNetworkInterface> > resultList;
1424
1425 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
1426 for (it = allList.begin(); it != allList.end(); ++it)
1427 {
1428 HostNetworkInterfaceType_T t;
1429 HRESULT hr = (*it)->COMGETTER(InterfaceType)(&t);
1430 if(FAILED(hr))
1431 return hr;
1432
1433 if(t == type)
1434 {
1435 (*it)->setVirtualBox(m->pParent);
1436 resultList.push_back (*it);
1437 }
1438 }
1439
1440 SafeIfaceArray<IHostNetworkInterface> filteredNetworkInterfaces (resultList);
1441 filteredNetworkInterfaces.detachTo(ComSafeArrayOutArg(aNetworkInterfaces));
1442
1443 return S_OK;
1444}
1445
1446STDMETHODIMP Host::FindUSBDeviceByAddress(IN_BSTR aAddress,
1447 IHostUSBDevice **aDevice)
1448{
1449#ifdef VBOX_WITH_USB
1450 CheckComArgStrNotEmptyOrNull(aAddress);
1451 CheckComArgOutPointerValid(aDevice);
1452
1453 *aDevice = NULL;
1454
1455 SafeIfaceArray<IHostUSBDevice> devsvec;
1456 HRESULT rc = COMGETTER(USBDevices) (ComSafeArrayAsOutParam(devsvec));
1457 if (FAILED(rc)) return rc;
1458
1459 for (size_t i = 0; i < devsvec.size(); ++i)
1460 {
1461 Bstr address;
1462 rc = devsvec[i]->COMGETTER(Address) (address.asOutParam());
1463 if (FAILED(rc)) return rc;
1464 if (address == aAddress)
1465 {
1466 return ComObjPtr<IHostUSBDevice> (devsvec[i]).queryInterfaceTo(aDevice);
1467 }
1468 }
1469
1470 return setErrorNoLog (VBOX_E_OBJECT_NOT_FOUND, tr (
1471 "Could not find a USB device with address '%ls'"),
1472 aAddress);
1473
1474#else /* !VBOX_WITH_USB */
1475 NOREF(aAddress);
1476 NOREF(aDevice);
1477 return E_NOTIMPL;
1478#endif /* !VBOX_WITH_USB */
1479}
1480
1481STDMETHODIMP Host::FindUSBDeviceById(IN_BSTR aId,
1482 IHostUSBDevice **aDevice)
1483{
1484#ifdef VBOX_WITH_USB
1485 CheckComArgExpr(aId, Guid (aId).isEmpty() == false);
1486 CheckComArgOutPointerValid(aDevice);
1487
1488 *aDevice = NULL;
1489
1490 SafeIfaceArray<IHostUSBDevice> devsvec;
1491 HRESULT rc = COMGETTER(USBDevices) (ComSafeArrayAsOutParam(devsvec));
1492 if (FAILED(rc)) return rc;
1493
1494 for (size_t i = 0; i < devsvec.size(); ++i)
1495 {
1496 Bstr id;
1497 rc = devsvec[i]->COMGETTER(Id) (id.asOutParam());
1498 if (FAILED(rc)) return rc;
1499 if (id == aId)
1500 {
1501 return ComObjPtr<IHostUSBDevice> (devsvec[i]).queryInterfaceTo(aDevice);
1502 }
1503 }
1504
1505 return setErrorNoLog (VBOX_E_OBJECT_NOT_FOUND, tr (
1506 "Could not find a USB device with uuid {%RTuuid}"),
1507 Guid (aId).raw());
1508
1509#else /* !VBOX_WITH_USB */
1510 NOREF(aId);
1511 NOREF(aDevice);
1512 return E_NOTIMPL;
1513#endif /* !VBOX_WITH_USB */
1514}
1515
1516// public methods only for internal purposes
1517////////////////////////////////////////////////////////////////////////////////
1518
1519HRESULT Host::loadSettings(const settings::Host &data)
1520{
1521 HRESULT rc = S_OK;
1522#ifdef VBOX_WITH_USB
1523 AutoCaller autoCaller(this);
1524 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1525
1526 AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1527
1528
1529 for (settings::USBDeviceFiltersList::const_iterator it = data.llUSBDeviceFilters.begin();
1530 it != data.llUSBDeviceFilters.end();
1531 ++it)
1532 {
1533 const settings::USBDeviceFilter &f = *it;
1534 ComObjPtr<HostUSBDeviceFilter> pFilter;
1535 pFilter.createObject();
1536 rc = pFilter->init(this, f);
1537 if (FAILED(rc)) break;
1538
1539 m->llUSBDeviceFilters.push_back(pFilter);
1540 pFilter->mInList = true;
1541
1542 /* notify the proxy (only when the filter is active) */
1543 if (pFilter->getData().mActive)
1544 {
1545 HostUSBDeviceFilter *flt = pFilter; /* resolve ambiguity */
1546 flt->getId() = m->pUSBProxyService->insertFilter(&pFilter->getData().mUSBFilter);
1547 }
1548 }
1549#else
1550 NOREF(data);
1551#endif /* VBOX_WITH_USB */
1552 return rc;
1553}
1554
1555HRESULT Host::saveSettings(settings::Host &data)
1556{
1557#ifdef VBOX_WITH_USB
1558 AutoCaller autoCaller(this);
1559 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1560
1561 AutoReadLock alock(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1562
1563 data.llUSBDeviceFilters.clear();
1564
1565 for (USBDeviceFilterList::const_iterator it = m->llUSBDeviceFilters.begin();
1566 it != m->llUSBDeviceFilters.end();
1567 ++it)
1568 {
1569 ComObjPtr<HostUSBDeviceFilter> pFilter = *it;
1570 settings::USBDeviceFilter f;
1571 pFilter->saveSettings(f);
1572 data.llUSBDeviceFilters.push_back(f);
1573 }
1574#else
1575 NOREF(data);
1576#endif /* VBOX_WITH_USB */
1577
1578 return S_OK;
1579}
1580
1581HRESULT Host::getDVDDrives(MediaList &list)
1582{
1583 HRESULT rc = S_OK;
1584
1585 Assert(isWriteLockOnCurrentThread());
1586
1587 try
1588 {
1589#if defined(RT_OS_WINDOWS)
1590 int sz = GetLogicalDriveStrings(0, NULL);
1591 TCHAR *hostDrives = new TCHAR[sz+1];
1592 GetLogicalDriveStrings(sz, hostDrives);
1593 wchar_t driveName[3] = { '?', ':', '\0' };
1594 TCHAR *p = hostDrives;
1595 do
1596 {
1597 if (GetDriveType(p) == DRIVE_CDROM)
1598 {
1599 driveName[0] = *p;
1600 ComObjPtr<Medium> hostDVDDriveObj;
1601 hostDVDDriveObj.createObject();
1602 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(driveName));
1603 list.push_back(hostDVDDriveObj);
1604 }
1605 p += _tcslen(p) + 1;
1606 }
1607 while (*p);
1608 delete[] hostDrives;
1609
1610#elif defined(RT_OS_SOLARIS)
1611# ifdef VBOX_USE_LIBHAL
1612 if (!getDVDInfoFromHal(list))
1613# endif
1614 // Not all Solaris versions ship with libhal.
1615 // So use a fallback approach similar to Linux.
1616 {
1617 if (RTEnvExistEx(RTENV_DEFAULT, "VBOX_CDROM"))
1618 {
1619 char *cdromEnv = RTEnvDupEx(RTENV_DEFAULT, "VBOX_CDROM");
1620 char *saveStr = NULL;
1621 char *cdromDrive = NULL;
1622 if (cdromEnv)
1623 cdromDrive = strtok_r(cdromEnv, ":", &saveStr);
1624 while (cdromDrive)
1625 {
1626 if (validateDevice(cdromDrive, true))
1627 {
1628 ComObjPtr<Medium> hostDVDDriveObj;
1629 hostDVDDriveObj.createObject();
1630 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(cdromDrive));
1631 list.push_back(hostDVDDriveObj);
1632 }
1633 cdromDrive = strtok_r(NULL, ":", &saveStr);
1634 }
1635 RTStrFree(cdromEnv);
1636 }
1637 else
1638 {
1639 // this might work on Solaris version older than Nevada.
1640 if (validateDevice("/cdrom/cdrom0", true))
1641 {
1642 ComObjPtr<Medium> hostDVDDriveObj;
1643 hostDVDDriveObj.createObject();
1644 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr("cdrom/cdrom0"));
1645 list.push_back(hostDVDDriveObj);
1646 }
1647
1648 // check the mounted drives
1649 parseMountTable(MNTTAB, list);
1650 }
1651 }
1652
1653#elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
1654 if (RT_SUCCESS(m->hostDrives.updateDVDs()))
1655 for (DriveInfoList::const_iterator it = m->hostDrives.DVDBegin();
1656 SUCCEEDED(rc) && it != m->hostDrives.DVDEnd(); ++it)
1657 {
1658 ComObjPtr<Medium> hostDVDDriveObj;
1659 Bstr location(it->mDevice);
1660 Bstr description(it->mDescription);
1661 if (SUCCEEDED(rc))
1662 rc = hostDVDDriveObj.createObject();
1663 if (SUCCEEDED(rc))
1664 rc = hostDVDDriveObj->init(m->pParent, DeviceType_DVD, location, description);
1665 if (SUCCEEDED(rc))
1666 list.push_back(hostDVDDriveObj);
1667 }
1668#elif defined(RT_OS_DARWIN)
1669 PDARWINDVD cur = DarwinGetDVDDrives();
1670 while (cur)
1671 {
1672 ComObjPtr<Medium> hostDVDDriveObj;
1673 hostDVDDriveObj.createObject();
1674 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(cur->szName));
1675 list.push_back(hostDVDDriveObj);
1676
1677 /* next */
1678 void *freeMe = cur;
1679 cur = cur->pNext;
1680 RTMemFree(freeMe);
1681 }
1682#else
1683 /* PORTME */
1684#endif
1685 }
1686 catch(std::bad_alloc &)
1687 {
1688 rc = E_OUTOFMEMORY;
1689 }
1690 return rc;
1691}
1692
1693/**
1694 * Internal implementation for COMGETTER(FloppyDrives) which can be called
1695 * from elsewhere. Caller must hold the Host object write lock!
1696 * @param list
1697 * @return
1698 */
1699HRESULT Host::getFloppyDrives(MediaList &list)
1700{
1701 HRESULT rc = S_OK;
1702
1703 Assert(isWriteLockOnCurrentThread());
1704
1705 try
1706 {
1707#ifdef RT_OS_WINDOWS
1708 int sz = GetLogicalDriveStrings(0, NULL);
1709 TCHAR *hostDrives = new TCHAR[sz+1];
1710 GetLogicalDriveStrings(sz, hostDrives);
1711 wchar_t driveName[3] = { '?', ':', '\0' };
1712 TCHAR *p = hostDrives;
1713 do
1714 {
1715 if (GetDriveType(p) == DRIVE_REMOVABLE)
1716 {
1717 driveName[0] = *p;
1718 ComObjPtr<Medium> hostFloppyDriveObj;
1719 hostFloppyDriveObj.createObject();
1720 hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, Bstr(driveName));
1721 list.push_back(hostFloppyDriveObj);
1722 }
1723 p += _tcslen(p) + 1;
1724 }
1725 while (*p);
1726 delete[] hostDrives;
1727#elif defined(RT_OS_LINUX)
1728 if (RT_SUCCESS(m->hostDrives.updateFloppies()))
1729 for (DriveInfoList::const_iterator it = m->hostDrives.FloppyBegin();
1730 SUCCEEDED(rc) && it != m->hostDrives.FloppyEnd(); ++it)
1731 {
1732 ComObjPtr<Medium> hostFloppyDriveObj;
1733 Bstr location(it->mDevice);
1734 Bstr description(it->mDescription);
1735 if (SUCCEEDED(rc))
1736 rc = hostFloppyDriveObj.createObject();
1737 if (SUCCEEDED(rc))
1738 rc = hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, location, description);
1739 if (SUCCEEDED(rc))
1740 list.push_back(hostFloppyDriveObj);
1741 }
1742#else
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