VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/HostImpl.cpp@ 43446

Last change on this file since 43446 was 43445, checked in by vboxsync, 12 years ago

Main/Metrics: Host network metrics, linux only (#6345)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 104.6 KB
Line 
1/* $Id: HostImpl.cpp 43445 2012-09-27 08:28:59Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation: Host
4 */
5
6/*
7 * Copyright (C) 2004-2012 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#define __STDC_LIMIT_MACROS
19#define __STDC_CONSTANT_MACROS
20
21// for some reason Windows burns in sdk\...\winsock.h if this isn't included first
22#include "VBox/com/ptr.h"
23
24#include "HostImpl.h"
25
26#ifdef VBOX_WITH_USB
27# include "HostUSBDeviceImpl.h"
28# include "USBDeviceFilterImpl.h"
29# include "USBProxyService.h"
30#endif // VBOX_WITH_USB
31
32#include "HostNetworkInterfaceImpl.h"
33#include "MachineImpl.h"
34#include "AutoCaller.h"
35#include "Logging.h"
36#include "Performance.h"
37
38#include "MediumImpl.h"
39#include "HostPower.h"
40
41#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
42# include <HostHardwareLinux.h>
43#endif
44
45#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
46# include <set>
47#endif
48
49#ifdef VBOX_WITH_RESOURCE_USAGE_API
50# include "PerformanceImpl.h"
51#endif /* VBOX_WITH_RESOURCE_USAGE_API */
52
53#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
54# include <VBox/VBoxNetCfg-win.h>
55#endif /* #if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT) */
56
57#ifdef RT_OS_LINUX
58# include <sys/ioctl.h>
59# include <errno.h>
60# include <net/if.h>
61# include <net/if_arp.h>
62#endif /* RT_OS_LINUX */
63
64#ifdef RT_OS_SOLARIS
65# include <fcntl.h>
66# include <unistd.h>
67# include <stropts.h>
68# include <errno.h>
69# include <limits.h>
70# include <stdio.h>
71# include <libdevinfo.h>
72# include <sys/mkdev.h>
73# include <sys/scsi/generic/inquiry.h>
74# include <net/if.h>
75# include <sys/socket.h>
76# include <sys/sockio.h>
77# include <net/if_arp.h>
78# include <net/if.h>
79# include <sys/types.h>
80# include <sys/stat.h>
81# include <sys/cdio.h>
82# include <sys/dkio.h>
83# include <sys/mnttab.h>
84# include <sys/mntent.h>
85/* Dynamic loading of libhal on Solaris hosts */
86# ifdef VBOX_USE_LIBHAL
87# include "vbox-libhal.h"
88extern "C" char *getfullrawname(char *);
89# endif
90# include "solaris/DynLoadLibSolaris.h"
91
92/**
93 * Solaris DVD drive list as returned by getDVDInfoFromDevTree().
94 */
95typedef struct SOLARISDVD
96{
97 struct SOLARISDVD *pNext;
98 char szDescription[512];
99 char szRawDiskPath[PATH_MAX];
100} SOLARISDVD;
101/** Pointer to a Solaris DVD descriptor. */
102typedef SOLARISDVD *PSOLARISDVD;
103
104#endif /* RT_OS_SOLARIS */
105
106#ifdef RT_OS_WINDOWS
107# define _WIN32_DCOM
108# include <windows.h>
109# include <shellapi.h>
110# define INITGUID
111# include <guiddef.h>
112# include <devguid.h>
113# include <objbase.h>
114//# include <setupapi.h>
115# include <shlobj.h>
116# include <cfgmgr32.h>
117
118#endif /* RT_OS_WINDOWS */
119
120#ifdef RT_OS_DARWIN
121# include "darwin/iokit.h"
122#endif
123
124#ifdef VBOX_WITH_CROGL
125#include <VBox/VBoxOGLTest.h>
126#endif /* VBOX_WITH_CROGL */
127
128#include <iprt/asm-amd64-x86.h>
129#include <iprt/string.h>
130#include <iprt/mp.h>
131#include <iprt/time.h>
132#include <iprt/param.h>
133#include <iprt/env.h>
134#include <iprt/mem.h>
135#include <iprt/system.h>
136#ifdef RT_OS_SOLARIS
137# include <iprt/path.h>
138# include <iprt/ctype.h>
139#endif
140#ifdef VBOX_WITH_HOSTNETIF_API
141# include "netif.h"
142#endif
143
144/* XXX Solaris: definitions in /usr/include/sys/regset.h clash with hm_svm.h */
145#undef DS
146#undef ES
147#undef CS
148#undef SS
149#undef FS
150#undef GS
151
152#include <VBox/usb.h>
153#include <VBox/vmm/hm_svm.h>
154#include <VBox/err.h>
155#include <VBox/settings.h>
156#include <VBox/sup.h>
157#include <iprt/x86.h>
158
159#include "VBox/com/MultiResult.h"
160
161#include <stdio.h>
162
163#include <algorithm>
164
165////////////////////////////////////////////////////////////////////////////////
166//
167// Host private data definition
168//
169////////////////////////////////////////////////////////////////////////////////
170
171struct Host::Data
172{
173 Data()
174 :
175 fDVDDrivesListBuilt(false),
176 fFloppyDrivesListBuilt(false)
177 {};
178
179 VirtualBox *pParent;
180
181 HostNetworkInterfaceList llNetIfs; // list of network interfaces
182
183#ifdef VBOX_WITH_USB
184 USBDeviceFilterList llChildren; // all USB device filters
185 USBDeviceFilterList llUSBDeviceFilters; // USB device filters in use by the USB proxy service
186
187 /** Pointer to the USBProxyService object. */
188 USBProxyService *pUSBProxyService;
189#endif /* VBOX_WITH_USB */
190
191 // list of host drives; lazily created by getDVDDrives() and getFloppyDrives(),
192 // and protected by the medium tree lock handle (including the bools).
193 MediaList llDVDDrives,
194 llFloppyDrives;
195 bool fDVDDrivesListBuilt,
196 fFloppyDrivesListBuilt;
197
198#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
199 /** Object with information about host drives */
200 VBoxMainDriveInfo hostDrives;
201#endif
202 /* Features that can be queried with GetProcessorFeature */
203 BOOL fVTSupported,
204 fLongModeSupported,
205 fPAESupported,
206 fNestedPagingSupported;
207
208 /* 3D hardware acceleration supported? */
209 BOOL f3DAccelerationSupported;
210
211 HostPowerService *pHostPowerService;
212};
213
214
215////////////////////////////////////////////////////////////////////////////////
216//
217// Constructor / destructor
218//
219////////////////////////////////////////////////////////////////////////////////
220
221HRESULT Host::FinalConstruct()
222{
223 return BaseFinalConstruct();
224}
225
226void Host::FinalRelease()
227{
228 uninit();
229 BaseFinalRelease();
230}
231
232/**
233 * Initializes the host object.
234 *
235 * @param aParent VirtualBox parent object.
236 */
237HRESULT Host::init(VirtualBox *aParent)
238{
239 HRESULT hrc;
240 LogFlowThisFunc(("aParent=%p\n", aParent));
241
242 /* Enclose the state transition NotReady->InInit->Ready */
243 AutoInitSpan autoInitSpan(this);
244 AssertReturn(autoInitSpan.isOk(), E_FAIL);
245
246 m = new Data();
247
248 m->pParent = aParent;
249
250#ifdef VBOX_WITH_USB
251 /*
252 * Create and initialize the USB Proxy Service.
253 */
254# if defined (RT_OS_DARWIN)
255 m->pUSBProxyService = new USBProxyServiceDarwin(this);
256# elif defined (RT_OS_LINUX)
257 m->pUSBProxyService = new USBProxyServiceLinux(this);
258# elif defined (RT_OS_OS2)
259 m->pUSBProxyService = new USBProxyServiceOs2(this);
260# elif defined (RT_OS_SOLARIS)
261 m->pUSBProxyService = new USBProxyServiceSolaris(this);
262# elif defined (RT_OS_WINDOWS)
263 m->pUSBProxyService = new USBProxyServiceWindows(this);
264# elif defined (RT_OS_FREEBSD)
265 m->pUSBProxyService = new USBProxyServiceFreeBSD(this);
266# else
267 m->pUSBProxyService = new USBProxyService(this);
268# endif
269 hrc = m->pUSBProxyService->init();
270 AssertComRCReturn(hrc, hrc);
271#endif /* VBOX_WITH_USB */
272
273#ifdef VBOX_WITH_RESOURCE_USAGE_API
274 registerMetrics(aParent->performanceCollector());
275#endif /* VBOX_WITH_RESOURCE_USAGE_API */
276 /* Create the list of network interfaces so their metrics get registered. */
277 updateNetIfList();
278
279#if defined (RT_OS_WINDOWS)
280 m->pHostPowerService = new HostPowerServiceWin(m->pParent);
281#elif defined (RT_OS_DARWIN)
282 m->pHostPowerService = new HostPowerServiceDarwin(m->pParent);
283#else
284 m->pHostPowerService = new HostPowerService(m->pParent);
285#endif
286
287 /* Cache the features reported by GetProcessorFeature. */
288 m->fVTSupported = false;
289 m->fLongModeSupported = false;
290 m->fPAESupported = false;
291 m->fNestedPagingSupported = false;
292
293 if (ASMHasCpuId())
294 {
295 uint32_t u32FeaturesECX;
296 uint32_t u32Dummy;
297 uint32_t u32FeaturesEDX;
298 uint32_t u32VendorEBX, u32VendorECX, u32VendorEDX, u32ExtFeatureEDX, u32ExtFeatureECX;
299
300 ASMCpuId(0, &u32Dummy, &u32VendorEBX, &u32VendorECX, &u32VendorEDX);
301 ASMCpuId(1, &u32Dummy, &u32Dummy, &u32FeaturesECX, &u32FeaturesEDX);
302 /* Query Extended features. */
303 ASMCpuId(0x80000001, &u32Dummy, &u32Dummy, &u32ExtFeatureECX, &u32ExtFeatureEDX);
304
305 m->fLongModeSupported = !!(u32ExtFeatureEDX & X86_CPUID_EXT_FEATURE_EDX_LONG_MODE);
306 m->fPAESupported = !!(u32FeaturesEDX & X86_CPUID_FEATURE_EDX_PAE);
307
308 if ( u32VendorEBX == X86_CPUID_VENDOR_INTEL_EBX
309 && u32VendorECX == X86_CPUID_VENDOR_INTEL_ECX
310 && u32VendorEDX == X86_CPUID_VENDOR_INTEL_EDX
311 )
312 {
313 /* Intel. */
314 if ( (u32FeaturesECX & X86_CPUID_FEATURE_ECX_VMX)
315 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR)
316 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR)
317 )
318 {
319 int rc = SUPR3QueryVTxSupported();
320 if (RT_SUCCESS(rc))
321 m->fVTSupported = true;
322 }
323 }
324 else
325 if ( u32VendorEBX == X86_CPUID_VENDOR_AMD_EBX
326 && u32VendorECX == X86_CPUID_VENDOR_AMD_ECX
327 && u32VendorEDX == X86_CPUID_VENDOR_AMD_EDX
328 )
329 {
330 /* AMD. */
331 if ( (u32ExtFeatureECX & X86_CPUID_AMD_FEATURE_ECX_SVM)
332 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR)
333 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR)
334 )
335 {
336 uint32_t u32SVMFeatureEDX;
337
338 m->fVTSupported = true;
339
340 /* Query AMD features. */
341 ASMCpuId(0x8000000A, &u32Dummy, &u32Dummy, &u32Dummy, &u32SVMFeatureEDX);
342 if (u32SVMFeatureEDX & AMD_CPUID_SVM_FEATURE_EDX_NESTED_PAGING)
343 m->fNestedPagingSupported = true;
344 }
345 }
346 else
347 if ( u32VendorEBX == X86_CPUID_VENDOR_VIA_EBX
348 && u32VendorECX == X86_CPUID_VENDOR_VIA_ECX
349 && u32VendorEDX == X86_CPUID_VENDOR_VIA_EDX
350 )
351 {
352 /* VIA. */
353 if ( (u32FeaturesECX & X86_CPUID_FEATURE_ECX_VMX)
354 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR)
355 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR)
356 )
357 {
358 int rc = SUPR3QueryVTxSupported();
359 if (RT_SUCCESS(rc))
360 m->fVTSupported = true;
361 }
362 }
363 }
364
365#if 0 /* needs testing */
366 if (m->fVTSupported)
367 {
368 uint32_t u32Caps = 0;
369
370 int rc = SUPR3QueryVTCaps(&u32Caps);
371 if (RT_SUCCESS(rc))
372 {
373 if (u32Caps & SUPVTCAPS_NESTED_PAGING)
374 m->fNestedPagingSupported = true;
375 }
376 /* else @todo; report BIOS trouble in some way. */
377 }
378#endif
379
380 /* Test for 3D hardware acceleration support */
381 m->f3DAccelerationSupported = false;
382
383#ifdef VBOX_WITH_CROGL
384 m->f3DAccelerationSupported = VBoxOglIs3DAccelerationSupported();
385#endif /* VBOX_WITH_CROGL */
386
387#if defined (RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
388 /* Extract the list of configured host-only interfaces */
389 std::set<Utf8Str> aConfiguredNames;
390 SafeArray<BSTR> aGlobalExtraDataKeys;
391 hrc = aParent->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
392 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
393 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); ++i)
394 {
395 Utf8Str strKey = aGlobalExtraDataKeys[i];
396
397 if (!strKey.startsWith("HostOnly/vboxnet"))
398 continue;
399
400 size_t pos = strKey.find("/", sizeof("HostOnly/vboxnet"));
401 if (pos != Utf8Str::npos)
402 aConfiguredNames.insert(strKey.substr(sizeof("HostOnly"),
403 pos - sizeof("HostOnly")));
404 }
405
406 for (std::set<Utf8Str>::const_iterator it = aConfiguredNames.begin();
407 it != aConfiguredNames.end();
408 ++it)
409 {
410 ComPtr<IHostNetworkInterface> hif;
411 ComPtr<IProgress> progress;
412
413 int r = NetIfCreateHostOnlyNetworkInterface(m->pParent,
414 hif.asOutParam(),
415 progress.asOutParam(),
416 it->c_str());
417 if (RT_FAILURE(r))
418 LogRel(("failed to create %s, error (0x%x)\n", it->c_str(), r));
419 }
420
421#endif /* defined (RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) */
422
423 /* Confirm a successful initialization */
424 autoInitSpan.setSucceeded();
425
426 return S_OK;
427}
428
429/**
430 * Uninitializes the host object and sets the ready flag to FALSE.
431 * Called either from FinalRelease() or by the parent when it gets destroyed.
432 */
433void Host::uninit()
434{
435 LogFlowThisFunc(("\n"));
436
437 /* Enclose the state transition Ready->InUninit->NotReady */
438 AutoUninitSpan autoUninitSpan(this);
439 if (autoUninitSpan.uninitDone())
440 return;
441
442#ifdef VBOX_WITH_RESOURCE_USAGE_API
443 PerformanceCollector *aCollector = m->pParent->performanceCollector();
444 unregisterMetrics (aCollector);
445 HostNetworkInterfaceList::iterator it;
446 for (it = m->llNetIfs.begin(); it != m->llNetIfs.end(); ++it)
447 (*it)->unregisterMetrics(aCollector, this);
448#endif /* VBOX_WITH_RESOURCE_USAGE_API */
449 m->llNetIfs.clear();
450
451#ifdef VBOX_WITH_USB
452 /* wait for USB proxy service to terminate before we uninit all USB
453 * devices */
454 LogFlowThisFunc(("Stopping USB proxy service...\n"));
455 delete m->pUSBProxyService;
456 m->pUSBProxyService = NULL;
457 LogFlowThisFunc(("Done stopping USB proxy service.\n"));
458#endif
459
460 delete m->pHostPowerService;
461
462#ifdef VBOX_WITH_USB
463 /* uninit all USB device filters still referenced by clients
464 * Note! HostUSBDeviceFilter::uninit() will modify llChildren. */
465 while (!m->llChildren.empty())
466 {
467 ComObjPtr<HostUSBDeviceFilter> &pChild = m->llChildren.front();
468 pChild->uninit();
469 }
470
471 m->llUSBDeviceFilters.clear();
472#endif
473
474 delete m;
475 m = NULL;
476}
477
478////////////////////////////////////////////////////////////////////////////////
479//
480// ISnapshot public methods
481//
482////////////////////////////////////////////////////////////////////////////////
483
484/**
485 * Returns a list of host DVD drives.
486 *
487 * @returns COM status code
488 * @param drives address of result pointer
489 */
490STDMETHODIMP Host::COMGETTER(DVDDrives)(ComSafeArrayOut(IMedium *, aDrives))
491{
492 CheckComArgOutSafeArrayPointerValid(aDrives);
493
494 AutoCaller autoCaller(this);
495 if (FAILED(autoCaller.rc())) return autoCaller.rc();
496
497 AutoWriteLock alock(m->pParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
498
499 MediaList *pList;
500 HRESULT rc = getDrives(DeviceType_DVD, true /* fRefresh */, pList);
501 if (SUCCEEDED(rc))
502 {
503 SafeIfaceArray<IMedium> array(*pList);
504 array.detachTo(ComSafeArrayOutArg(aDrives));
505 }
506
507 return rc;
508}
509
510/**
511 * Returns a list of host floppy drives.
512 *
513 * @returns COM status code
514 * @param drives address of result pointer
515 */
516STDMETHODIMP Host::COMGETTER(FloppyDrives)(ComSafeArrayOut(IMedium *, aDrives))
517{
518 CheckComArgOutPointerValid(aDrives);
519
520 AutoCaller autoCaller(this);
521 if (FAILED(autoCaller.rc())) return autoCaller.rc();
522
523 AutoWriteLock alock(m->pParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
524
525 MediaList *pList;
526 HRESULT rc = getDrives(DeviceType_Floppy, true /* fRefresh */, pList);
527 if (SUCCEEDED(rc))
528 {
529 SafeIfaceArray<IMedium> collection(*pList);
530 collection.detachTo(ComSafeArrayOutArg(aDrives));
531 }
532
533 return rc;
534}
535
536
537#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
538# define VBOX_APP_NAME L"VirtualBox"
539
540static int vboxNetWinAddComponent(std::list< ComObjPtr<HostNetworkInterface> > *pPist,
541 INetCfgComponent *pncc)
542{
543 LPWSTR lpszName;
544 GUID IfGuid;
545 HRESULT hr;
546 int rc = VERR_GENERAL_FAILURE;
547
548 hr = pncc->GetDisplayName( &lpszName );
549 Assert(hr == S_OK);
550 if (hr == S_OK)
551 {
552 Bstr name((CBSTR)lpszName);
553
554 hr = pncc->GetInstanceGuid(&IfGuid);
555 Assert(hr == S_OK);
556 if (hr == S_OK)
557 {
558 /* create a new object and add it to the list */
559 ComObjPtr<HostNetworkInterface> iface;
560 iface.createObject();
561 /* remove the curly bracket at the end */
562 if (SUCCEEDED(iface->init (name, name, Guid (IfGuid), HostNetworkInterfaceType_Bridged)))
563 {
564// iface->setVirtualBox(m->pParent);
565 pPist->push_back(iface);
566 rc = VINF_SUCCESS;
567 }
568 else
569 {
570 Assert(0);
571 }
572 }
573 CoTaskMemFree(lpszName);
574 }
575
576 return rc;
577}
578#endif /* defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT) */
579
580/**
581 * Returns a list of host network interfaces.
582 *
583 * @returns COM status code
584 * @param drives address of result pointer
585 */
586STDMETHODIMP Host::COMGETTER(NetworkInterfaces)(ComSafeArrayOut(IHostNetworkInterface*, aNetworkInterfaces))
587{
588#if defined(RT_OS_WINDOWS) || defined(VBOX_WITH_NETFLT) /*|| defined(RT_OS_OS2)*/
589 if (ComSafeArrayOutIsNull(aNetworkInterfaces))
590 return E_POINTER;
591
592 AutoCaller autoCaller(this);
593 if (FAILED(autoCaller.rc())) return autoCaller.rc();
594
595 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
596# ifdef VBOX_WITH_HOSTNETIF_API
597 int rc = updateNetIfList();
598 if (rc)
599 {
600 Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
601 }
602
603 SafeIfaceArray<IHostNetworkInterface> networkInterfaces (m->llNetIfs);
604 networkInterfaces.detachTo(ComSafeArrayOutArg(aNetworkInterfaces));
605
606 return S_OK;
607
608# else
609 std::list<ComObjPtr<HostNetworkInterface> > list;
610
611# if defined(RT_OS_DARWIN)
612 PDARWINETHERNIC pEtherNICs = DarwinGetEthernetControllers();
613 while (pEtherNICs)
614 {
615 ComObjPtr<HostNetworkInterface> IfObj;
616 IfObj.createObject();
617 if (SUCCEEDED(IfObj->init(Bstr(pEtherNICs->szName), Guid(pEtherNICs->Uuid), HostNetworkInterfaceType_Bridged)))
618 list.push_back(IfObj);
619
620 /* next, free current */
621 void *pvFree = pEtherNICs;
622 pEtherNICs = pEtherNICs->pNext;
623 RTMemFree(pvFree);
624 }
625
626# elif defined RT_OS_WINDOWS
627# ifndef VBOX_WITH_NETFLT
628 hr = E_NOTIMPL;
629# else /* # if defined VBOX_WITH_NETFLT */
630 INetCfg *pNc;
631 INetCfgComponent *pMpNcc;
632 INetCfgComponent *pTcpIpNcc;
633 LPWSTR lpszApp;
634 HRESULT hr;
635 IEnumNetCfgBindingPath *pEnumBp;
636 INetCfgBindingPath *pBp;
637 IEnumNetCfgBindingInterface *pEnumBi;
638 INetCfgBindingInterface *pBi;
639
640 /* we are using the INetCfg API for getting the list of miniports */
641 hr = VBoxNetCfgWinQueryINetCfg( FALSE,
642 VBOX_APP_NAME,
643 &pNc,
644 &lpszApp );
645 Assert(hr == S_OK);
646 if (hr == S_OK)
647 {
648# ifdef VBOX_NETFLT_ONDEMAND_BIND
649 /* for the protocol-based approach for now we just get all miniports the MS_TCPIP protocol binds to */
650 hr = pNc->FindComponent(L"MS_TCPIP", &pTcpIpNcc);
651# else
652 /* for the filter-based approach we get all miniports our filter (sun_VBoxNetFlt)is bound to */
653 hr = pNc->FindComponent(L"sun_VBoxNetFlt", &pTcpIpNcc);
654# ifndef VBOX_WITH_HARDENING
655 if (hr != S_OK)
656 {
657 /* TODO: try to install the netflt from here */
658 }
659# endif
660
661# endif
662
663 if (hr == S_OK)
664 {
665 hr = VBoxNetCfgWinGetBindingPathEnum(pTcpIpNcc, EBP_BELOW, &pEnumBp);
666 Assert(hr == S_OK);
667 if ( hr == S_OK )
668 {
669 hr = VBoxNetCfgWinGetFirstBindingPath(pEnumBp, &pBp);
670 Assert(hr == S_OK || hr == S_FALSE);
671 while( hr == S_OK )
672 {
673 /* S_OK == enabled, S_FALSE == disabled */
674 if (pBp->IsEnabled() == S_OK)
675 {
676 hr = VBoxNetCfgWinGetBindingInterfaceEnum(pBp, &pEnumBi);
677 Assert(hr == S_OK);
678 if ( hr == S_OK )
679 {
680 hr = VBoxNetCfgWinGetFirstBindingInterface(pEnumBi, &pBi);
681 Assert(hr == S_OK);
682 while(hr == S_OK)
683 {
684 hr = pBi->GetLowerComponent( &pMpNcc );
685 Assert(hr == S_OK);
686 if (hr == S_OK)
687 {
688 ULONG uComponentStatus;
689 hr = pMpNcc->GetDeviceStatus(&uComponentStatus);
690 Assert(hr == S_OK);
691 if (hr == S_OK)
692 {
693 if (uComponentStatus == 0)
694 {
695 vboxNetWinAddComponent(&list, pMpNcc);
696 }
697 }
698 VBoxNetCfgWinReleaseRef( pMpNcc );
699 }
700 VBoxNetCfgWinReleaseRef(pBi);
701
702 hr = VBoxNetCfgWinGetNextBindingInterface(pEnumBi, &pBi);
703 }
704 VBoxNetCfgWinReleaseRef(pEnumBi);
705 }
706 }
707 VBoxNetCfgWinReleaseRef(pBp);
708
709 hr = VBoxNetCfgWinGetNextBindingPath(pEnumBp, &pBp);
710 }
711 VBoxNetCfgWinReleaseRef(pEnumBp);
712 }
713 VBoxNetCfgWinReleaseRef(pTcpIpNcc);
714 }
715 else
716 {
717 LogRel(("failed to get the sun_VBoxNetFlt component, error (0x%x)\n", hr));
718 }
719
720 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE);
721 }
722# endif /* # if defined VBOX_WITH_NETFLT */
723
724
725# elif defined RT_OS_LINUX
726 int sock = socket(AF_INET, SOCK_DGRAM, 0);
727 if (sock >= 0)
728 {
729 char pBuffer[2048];
730 struct ifconf ifConf;
731 ifConf.ifc_len = sizeof(pBuffer);
732 ifConf.ifc_buf = pBuffer;
733 if (ioctl(sock, SIOCGIFCONF, &ifConf) >= 0)
734 {
735 for (struct ifreq *pReq = ifConf.ifc_req; (char*)pReq < pBuffer + ifConf.ifc_len; pReq++)
736 {
737 if (ioctl(sock, SIOCGIFHWADDR, pReq) >= 0)
738 {
739 if (pReq->ifr_hwaddr.sa_family == ARPHRD_ETHER)
740 {
741 RTUUID uuid;
742 Assert(sizeof(uuid) <= sizeof(*pReq));
743 memcpy(&uuid, pReq, sizeof(uuid));
744
745 ComObjPtr<HostNetworkInterface> IfObj;
746 IfObj.createObject();
747 if (SUCCEEDED(IfObj->init(Bstr(pReq->ifr_name), Guid(uuid), HostNetworkInterfaceType_Bridged)))
748 list.push_back(IfObj);
749 }
750 }
751 }
752 }
753 close(sock);
754 }
755# endif /* RT_OS_LINUX */
756
757 SafeIfaceArray<IHostNetworkInterface> networkInterfaces (list);
758 networkInterfaces.detachTo(ComSafeArrayOutArg(aNetworkInterfaces));
759
760 return S_OK;
761
762# endif
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 HRESULT 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 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
805
806 HRESULT 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 number of installed physical processor cores.
857 *
858 * @returns COM status code
859 * @param count address of result variable
860 */
861STDMETHODIMP Host::COMGETTER(ProcessorCoreCount)(ULONG *aCount)
862{
863 CheckComArgOutPointerValid(aCount);
864 // no locking required
865
866 return E_NOTIMPL;
867}
868
869/**
870 * Returns the (approximate) maximum speed of the given host CPU in MHz
871 *
872 * @returns COM status code
873 * @param cpu id to get info for.
874 * @param speed address of result variable, speed is 0 if unknown or aCpuId is invalid.
875 */
876STDMETHODIMP Host::GetProcessorSpeed(ULONG aCpuId, ULONG *aSpeed)
877{
878 CheckComArgOutPointerValid(aSpeed);
879 // no locking required
880
881 *aSpeed = RTMpGetMaxFrequency(aCpuId);
882 return S_OK;
883}
884
885/**
886 * Returns a description string for the host CPU
887 *
888 * @returns COM status code
889 * @param cpu id to get info for.
890 * @param description address of result variable, empty string if not known or aCpuId is invalid.
891 */
892STDMETHODIMP Host::GetProcessorDescription(ULONG aCpuId, BSTR *aDescription)
893{
894 CheckComArgOutPointerValid(aDescription);
895 // no locking required
896
897 char szCPUModel[80];
898 int vrc = RTMpGetDescription(aCpuId, szCPUModel, sizeof(szCPUModel));
899 if (RT_FAILURE(vrc))
900 return E_FAIL; /** @todo error reporting? */
901 Bstr (szCPUModel).cloneTo(aDescription);
902 return S_OK;
903}
904
905/**
906 * Returns whether a host processor feature is supported or not
907 *
908 * @returns COM status code
909 * @param Feature to query.
910 * @param address of supported bool result variable
911 */
912STDMETHODIMP Host::GetProcessorFeature(ProcessorFeature_T aFeature, BOOL *aSupported)
913{
914 CheckComArgOutPointerValid(aSupported);
915 AutoCaller autoCaller(this);
916 if (FAILED(autoCaller.rc())) return autoCaller.rc();
917
918 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
919
920 switch (aFeature)
921 {
922 case ProcessorFeature_HWVirtEx:
923 *aSupported = m->fVTSupported;
924 break;
925
926 case ProcessorFeature_PAE:
927 *aSupported = m->fPAESupported;
928 break;
929
930 case ProcessorFeature_LongMode:
931 *aSupported = m->fLongModeSupported;
932 break;
933
934 case ProcessorFeature_NestedPaging:
935 *aSupported = m->fNestedPagingSupported;
936 break;
937
938 default:
939 ReturnComNotImplemented();
940 }
941 return S_OK;
942}
943
944/**
945 * Returns the specific CPUID leaf.
946 *
947 * @returns COM status code
948 * @param aCpuId The CPU number. Mostly ignored.
949 * @param aLeaf The leaf number.
950 * @param aSubLeaf The sub-leaf number.
951 * @param aValEAX Where to return EAX.
952 * @param aValEBX Where to return EBX.
953 * @param aValECX Where to return ECX.
954 * @param aValEDX Where to return EDX.
955 */
956STDMETHODIMP Host::GetProcessorCPUIDLeaf(ULONG aCpuId, ULONG aLeaf, ULONG aSubLeaf,
957 ULONG *aValEAX, ULONG *aValEBX, ULONG *aValECX, ULONG *aValEDX)
958{
959 CheckComArgOutPointerValid(aValEAX);
960 CheckComArgOutPointerValid(aValEBX);
961 CheckComArgOutPointerValid(aValECX);
962 CheckComArgOutPointerValid(aValEDX);
963 // no locking required
964
965 /* Check that the CPU is online. */
966 /** @todo later use RTMpOnSpecific. */
967 if (!RTMpIsCpuOnline(aCpuId))
968 return RTMpIsCpuPresent(aCpuId)
969 ? setError(E_FAIL, tr("CPU no.%u is not present"), aCpuId)
970 : setError(E_FAIL, tr("CPU no.%u is not online"), aCpuId);
971
972 uint32_t uEAX, uEBX, uECX, uEDX;
973 ASMCpuId_Idx_ECX(aLeaf, aSubLeaf, &uEAX, &uEBX, &uECX, &uEDX);
974 *aValEAX = uEAX;
975 *aValEBX = uEBX;
976 *aValECX = uECX;
977 *aValEDX = uEDX;
978
979 return S_OK;
980}
981
982/**
983 * Returns the amount of installed system memory in megabytes
984 *
985 * @returns COM status code
986 * @param size address of result variable
987 */
988STDMETHODIMP Host::COMGETTER(MemorySize)(ULONG *aSize)
989{
990 CheckComArgOutPointerValid(aSize);
991 // no locking required
992
993 /* @todo This is an ugly hack. There must be a function in IPRT for that. */
994 pm::CollectorHAL *hal = pm::createHAL();
995 if (!hal)
996 return E_FAIL;
997 ULONG tmp;
998 int rc = hal->getHostMemoryUsage(aSize, &tmp, &tmp);
999 *aSize /= 1024;
1000 delete hal;
1001 return rc;
1002}
1003
1004/**
1005 * Returns the current system memory free space in megabytes
1006 *
1007 * @returns COM status code
1008 * @param available address of result variable
1009 */
1010STDMETHODIMP Host::COMGETTER(MemoryAvailable)(ULONG *aAvailable)
1011{
1012 CheckComArgOutPointerValid(aAvailable);
1013 // no locking required
1014
1015 /* @todo This is an ugly hack. There must be a function in IPRT for that. */
1016 pm::CollectorHAL *hal = pm::createHAL();
1017 if (!hal)
1018 return E_FAIL;
1019 ULONG tmp;
1020 int rc = hal->getHostMemoryUsage(&tmp, &tmp, aAvailable);
1021 *aAvailable /= 1024;
1022 delete hal;
1023 return rc;
1024}
1025
1026/**
1027 * Returns the name string of the host operating system
1028 *
1029 * @returns COM status code
1030 * @param os address of result variable
1031 */
1032STDMETHODIMP Host::COMGETTER(OperatingSystem)(BSTR *aOs)
1033{
1034 CheckComArgOutPointerValid(aOs);
1035 // no locking required
1036
1037 char szOSName[80];
1038 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szOSName, sizeof(szOSName));
1039 if (RT_FAILURE(vrc))
1040 return E_FAIL; /** @todo error reporting? */
1041 Bstr (szOSName).cloneTo(aOs);
1042 return S_OK;
1043}
1044
1045/**
1046 * Returns the version string of the host operating system
1047 *
1048 * @returns COM status code
1049 * @param os address of result variable
1050 */
1051STDMETHODIMP Host::COMGETTER(OSVersion)(BSTR *aVersion)
1052{
1053 CheckComArgOutPointerValid(aVersion);
1054 // no locking required
1055
1056 /* Get the OS release. Reserve some buffer space for the service pack. */
1057 char szOSRelease[128];
1058 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOSRelease, sizeof(szOSRelease) - 32);
1059 if (RT_FAILURE(vrc))
1060 return E_FAIL; /** @todo error reporting? */
1061
1062 /* Append the service pack if present. */
1063 char szOSServicePack[80];
1064 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szOSServicePack, sizeof(szOSServicePack));
1065 if (RT_FAILURE(vrc))
1066 {
1067 if (vrc != VERR_NOT_SUPPORTED)
1068 return E_FAIL; /** @todo error reporting? */
1069 szOSServicePack[0] = '\0';
1070 }
1071 if (szOSServicePack[0] != '\0')
1072 {
1073 char *psz = strchr(szOSRelease, '\0');
1074 RTStrPrintf(psz, &szOSRelease[sizeof(szOSRelease)] - psz, "sp%s", szOSServicePack);
1075 }
1076
1077 Bstr(szOSRelease).cloneTo(aVersion);
1078 return S_OK;
1079}
1080
1081/**
1082 * Returns the current host time in milliseconds since 1970-01-01 UTC.
1083 *
1084 * @returns COM status code
1085 * @param time address of result variable
1086 */
1087STDMETHODIMP Host::COMGETTER(UTCTime)(LONG64 *aUTCTime)
1088{
1089 CheckComArgOutPointerValid(aUTCTime);
1090 // no locking required
1091
1092 RTTIMESPEC now;
1093 *aUTCTime = RTTimeSpecGetMilli(RTTimeNow(&now));
1094
1095 return S_OK;
1096}
1097
1098STDMETHODIMP Host::COMGETTER(Acceleration3DAvailable)(BOOL *aSupported)
1099{
1100 CheckComArgOutPointerValid(aSupported);
1101 AutoCaller autoCaller(this);
1102 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1103
1104 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1105
1106 *aSupported = m->f3DAccelerationSupported;
1107
1108#ifdef DEBUG_misha
1109 AssertMsgFailed(("should not be here any more!\n"));
1110#endif
1111
1112 return S_OK;
1113}
1114
1115STDMETHODIMP Host::CreateHostOnlyNetworkInterface(IHostNetworkInterface **aHostNetworkInterface,
1116 IProgress **aProgress)
1117{
1118 CheckComArgOutPointerValid(aHostNetworkInterface);
1119 CheckComArgOutPointerValid(aProgress);
1120
1121 AutoCaller autoCaller(this);
1122 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1123
1124#ifdef VBOX_WITH_HOSTNETIF_API
1125 /* No need to lock anything. If there ever will - watch out, the function
1126 * called below grabs the VirtualBox lock. */
1127
1128 int r = NetIfCreateHostOnlyNetworkInterface(m->pParent, aHostNetworkInterface, aProgress);
1129 if (RT_SUCCESS(r))
1130 {
1131 if (!*aHostNetworkInterface)
1132 return setError(E_FAIL,
1133 tr("Unable to create a host network interface"));
1134
1135#if !defined(RT_OS_WINDOWS)
1136 Bstr tmpAddr, tmpMask, tmpName;
1137 HRESULT hrc;
1138 hrc = (*aHostNetworkInterface)->COMGETTER(Name)(tmpName.asOutParam());
1139 ComAssertComRCRet(hrc, hrc);
1140 hrc = (*aHostNetworkInterface)->COMGETTER(IPAddress)(tmpAddr.asOutParam());
1141 ComAssertComRCRet(hrc, hrc);
1142 hrc = (*aHostNetworkInterface)->COMGETTER(NetworkMask)(tmpMask.asOutParam());
1143 ComAssertComRCRet(hrc, hrc);
1144 /*
1145 * We need to write the default IP address and mask to extra data now,
1146 * so the interface gets re-created after vboxnetadp.ko reload.
1147 * Note that we avoid calling EnableStaticIpConfig since it would
1148 * change the address on host's interface as well and we want to
1149 * postpone the change until VM actually starts.
1150 */
1151 hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPAddress",
1152 tmpName.raw()).raw(),
1153 tmpAddr.raw());
1154 ComAssertComRCRet(hrc, hrc);
1155
1156 hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPNetMask",
1157 tmpName.raw()).raw(),
1158 tmpMask.raw());
1159 ComAssertComRCRet(hrc, hrc);
1160#endif
1161 }
1162
1163 return S_OK;
1164#else
1165 return E_NOTIMPL;
1166#endif
1167}
1168
1169STDMETHODIMP Host::RemoveHostOnlyNetworkInterface(IN_BSTR aId,
1170 IProgress **aProgress)
1171{
1172 CheckComArgOutPointerValid(aProgress);
1173
1174 AutoCaller autoCaller(this);
1175 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1176
1177#ifdef VBOX_WITH_HOSTNETIF_API
1178 /* No need to lock anything, the code below does not touch the state
1179 * of the host object. If that ever changes then check for lock order
1180 * violations with the called functions. */
1181
1182 Bstr name;
1183 HRESULT rc;
1184
1185 /* first check whether an interface with the given name already exists */
1186 {
1187 ComPtr<IHostNetworkInterface> iface;
1188 if (FAILED(FindHostNetworkInterfaceById(aId,
1189 iface.asOutParam())))
1190 return setError(VBOX_E_OBJECT_NOT_FOUND,
1191 tr("Host network interface with UUID {%RTuuid} does not exist"),
1192 Guid (aId).raw());
1193 rc = iface->COMGETTER(Name)(name.asOutParam());
1194 ComAssertComRCRet(rc, rc);
1195 }
1196
1197 int r = NetIfRemoveHostOnlyNetworkInterface(m->pParent, Guid(aId).ref(), aProgress);
1198 if (RT_SUCCESS(r))
1199 {
1200 /* Drop configuration parameters for removed interface */
1201 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPAddress", name.raw()).raw(), NULL);
1202 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPNetMask", name.raw()).raw(), NULL);
1203 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPV6Address", name.raw()).raw(), NULL);
1204 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPV6NetMask", name.raw()).raw(), NULL);
1205
1206 return S_OK;
1207 }
1208
1209 return r == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
1210#else
1211 return E_NOTIMPL;
1212#endif
1213}
1214
1215STDMETHODIMP Host::CreateUSBDeviceFilter(IN_BSTR aName,
1216 IHostUSBDeviceFilter **aFilter)
1217{
1218#ifdef VBOX_WITH_USB
1219 CheckComArgStrNotEmptyOrNull(aName);
1220 CheckComArgOutPointerValid(aFilter);
1221
1222 AutoCaller autoCaller(this);
1223 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1224
1225 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1226
1227 ComObjPtr<HostUSBDeviceFilter> filter;
1228 filter.createObject();
1229 HRESULT rc = filter->init(this, aName);
1230 ComAssertComRCRet(rc, rc);
1231 rc = filter.queryInterfaceTo(aFilter);
1232 AssertComRCReturn(rc, rc);
1233 return S_OK;
1234#else
1235 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1236 * extended error info to indicate that USB is simply not available
1237 * (w/o treating it as a failure), for example, as in OSE. */
1238 NOREF(aName);
1239 NOREF(aFilter);
1240 ReturnComNotImplemented();
1241#endif
1242}
1243
1244STDMETHODIMP Host::InsertUSBDeviceFilter(ULONG aPosition,
1245 IHostUSBDeviceFilter *aFilter)
1246{
1247#ifdef VBOX_WITH_USB
1248 CheckComArgNotNull(aFilter);
1249
1250 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1251 AutoCaller autoCaller(this);
1252 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1253
1254 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1255
1256 clearError();
1257 MultiResult rc = checkUSBProxyService();
1258 if (FAILED(rc)) return rc;
1259
1260 ComObjPtr<HostUSBDeviceFilter> pFilter;
1261 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
1262 it != m->llChildren.end();
1263 ++it)
1264 {
1265 if (*it == aFilter)
1266 {
1267 pFilter = *it;
1268 break;
1269 }
1270 }
1271 if (pFilter.isNull())
1272 return setError(VBOX_E_INVALID_OBJECT_STATE,
1273 tr("The given USB device filter is not created within this VirtualBox instance"));
1274
1275 if (pFilter->mInList)
1276 return setError(E_INVALIDARG,
1277 tr("The given USB device filter is already in the list"));
1278
1279 /* iterate to the position... */
1280 USBDeviceFilterList::iterator itPos = m->llUSBDeviceFilters.begin();
1281 std::advance(itPos, aPosition);
1282 /* ...and insert */
1283 m->llUSBDeviceFilters.insert(itPos, pFilter);
1284 pFilter->mInList = true;
1285
1286 /* notify the proxy (only when the filter is active) */
1287 if ( m->pUSBProxyService->isActive()
1288 && pFilter->getData().mActive)
1289 {
1290 ComAssertRet(pFilter->getId() == NULL, E_FAIL);
1291 pFilter->getId() = m->pUSBProxyService->insertFilter(&pFilter->getData().mUSBFilter);
1292 }
1293
1294 // save the global settings; for that we should hold only the VirtualBox lock
1295 alock.release();
1296 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
1297 return rc = m->pParent->saveSettings();
1298#else
1299 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1300 * extended error info to indicate that USB is simply not available
1301 * (w/o treating it as a failure), for example, as in OSE. */
1302 NOREF(aPosition);
1303 NOREF(aFilter);
1304 ReturnComNotImplemented();
1305#endif
1306}
1307
1308STDMETHODIMP Host::RemoveUSBDeviceFilter(ULONG aPosition)
1309{
1310#ifdef VBOX_WITH_USB
1311
1312 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1313 AutoCaller autoCaller(this);
1314 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1315
1316 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1317
1318 clearError();
1319 MultiResult rc = checkUSBProxyService();
1320 if (FAILED(rc)) return rc;
1321
1322 if (!m->llUSBDeviceFilters.size())
1323 return setError(E_INVALIDARG,
1324 tr("The USB device filter list is empty"));
1325
1326 if (aPosition >= m->llUSBDeviceFilters.size())
1327 return setError(E_INVALIDARG,
1328 tr("Invalid position: %lu (must be in range [0, %lu])"),
1329 aPosition, m->llUSBDeviceFilters.size() - 1);
1330
1331 ComObjPtr<HostUSBDeviceFilter> filter;
1332 {
1333 /* iterate to the position... */
1334 USBDeviceFilterList::iterator it = m->llUSBDeviceFilters.begin();
1335 std::advance (it, aPosition);
1336 /* ...get an element from there... */
1337 filter = *it;
1338 /* ...and remove */
1339 filter->mInList = false;
1340 m->llUSBDeviceFilters.erase(it);
1341 }
1342
1343 /* notify the proxy (only when the filter is active) */
1344 if (m->pUSBProxyService->isActive() && filter->getData().mActive)
1345 {
1346 ComAssertRet(filter->getId() != NULL, E_FAIL);
1347 m->pUSBProxyService->removeFilter(filter->getId());
1348 filter->getId() = NULL;
1349 }
1350
1351 // save the global settings; for that we should hold only the VirtualBox lock
1352 alock.release();
1353 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
1354 return rc = m->pParent->saveSettings();
1355#else
1356 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1357 * extended error info to indicate that USB is simply not available
1358 * (w/o treating it as a failure), for example, as in OSE. */
1359 NOREF(aPosition);
1360 ReturnComNotImplemented();
1361#endif
1362}
1363
1364STDMETHODIMP Host::FindHostDVDDrive(IN_BSTR aName, IMedium **aDrive)
1365{
1366 CheckComArgStrNotEmptyOrNull(aName);
1367 CheckComArgOutPointerValid(aDrive);
1368
1369 ComObjPtr<Medium>medium;
1370 HRESULT rc = findHostDriveByNameOrId(DeviceType_DVD, Utf8Str(aName), medium);
1371 if (SUCCEEDED(rc))
1372 return medium.queryInterfaceTo(aDrive);
1373 else
1374 return setError(rc, Medium::tr("The host DVD drive named '%ls' could not be found"), aName);
1375}
1376
1377STDMETHODIMP Host::FindHostFloppyDrive(IN_BSTR aName, IMedium **aDrive)
1378{
1379 CheckComArgStrNotEmptyOrNull(aName);
1380 CheckComArgOutPointerValid(aDrive);
1381
1382 *aDrive = NULL;
1383
1384 ComObjPtr<Medium>medium;
1385 HRESULT rc = findHostDriveByNameOrId(DeviceType_Floppy, Utf8Str(aName), medium);
1386 if (SUCCEEDED(rc))
1387 return medium.queryInterfaceTo(aDrive);
1388 else
1389 return setError(rc, Medium::tr("The host floppy drive named '%ls' could not be found"), aName);
1390}
1391
1392STDMETHODIMP Host::FindHostNetworkInterfaceByName(IN_BSTR name, IHostNetworkInterface **networkInterface)
1393{
1394#ifndef VBOX_WITH_HOSTNETIF_API
1395 return E_NOTIMPL;
1396#else
1397 if (!name)
1398 return E_INVALIDARG;
1399 if (!networkInterface)
1400 return E_POINTER;
1401
1402 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1403
1404 *networkInterface = NULL;
1405 ComObjPtr<HostNetworkInterface> found;
1406 int rc = updateNetIfList();
1407 if (RT_FAILURE(rc))
1408 {
1409 Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
1410 return E_FAIL;
1411 }
1412 HostNetworkInterfaceList::iterator it;
1413 for (it = m->llNetIfs.begin(); it != m->llNetIfs.end(); ++it)
1414 {
1415 Bstr n;
1416 (*it)->COMGETTER(Name) (n.asOutParam());
1417 if (n == name)
1418 found = *it;
1419 }
1420
1421 if (!found)
1422 return setError(E_INVALIDARG,
1423 HostNetworkInterface::tr("The host network interface with the given name could not be found"));
1424
1425 return found.queryInterfaceTo(networkInterface);
1426#endif
1427}
1428
1429STDMETHODIMP Host::FindHostNetworkInterfaceById(IN_BSTR id, IHostNetworkInterface **networkInterface)
1430{
1431#ifndef VBOX_WITH_HOSTNETIF_API
1432 return E_NOTIMPL;
1433#else
1434 if (Guid(id).isEmpty())
1435 return E_INVALIDARG;
1436 if (!networkInterface)
1437 return E_POINTER;
1438
1439 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1440
1441 *networkInterface = NULL;
1442 ComObjPtr<HostNetworkInterface> found;
1443 int rc = updateNetIfList();
1444 if (RT_FAILURE(rc))
1445 {
1446 Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
1447 return E_FAIL;
1448 }
1449 HostNetworkInterfaceList::iterator it;
1450 for (it = m->llNetIfs.begin(); it != m->llNetIfs.end(); ++it)
1451 {
1452 Bstr g;
1453 (*it)->COMGETTER(Id) (g.asOutParam());
1454 if (g == id)
1455 found = *it;
1456 }
1457
1458 if (!found)
1459 return setError(E_INVALIDARG,
1460 HostNetworkInterface::tr("The host network interface with the given GUID could not be found"));
1461
1462 return found.queryInterfaceTo(networkInterface);
1463#endif
1464}
1465
1466STDMETHODIMP Host::FindHostNetworkInterfacesOfType(HostNetworkInterfaceType_T type,
1467 ComSafeArrayOut(IHostNetworkInterface *, aNetworkInterfaces))
1468{
1469#ifdef VBOX_WITH_HOSTNETIF_API
1470 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1471
1472 int rc = updateNetIfList();
1473 if (RT_FAILURE(rc))
1474 return E_FAIL;
1475
1476 HostNetworkInterfaceList resultList;
1477
1478 HostNetworkInterfaceList::iterator it;
1479 for (it = m->llNetIfs.begin(); it != m->llNetIfs.end(); ++it)
1480 {
1481 HostNetworkInterfaceType_T t;
1482 HRESULT hr = (*it)->COMGETTER(InterfaceType)(&t);
1483 if (FAILED(hr))
1484 return hr;
1485
1486 if (t == type)
1487 resultList.push_back (*it);
1488 }
1489
1490 SafeIfaceArray<IHostNetworkInterface> filteredNetworkInterfaces (resultList);
1491 filteredNetworkInterfaces.detachTo(ComSafeArrayOutArg(aNetworkInterfaces));
1492
1493 return S_OK;
1494#else
1495 return E_NOTIMPL;
1496#endif
1497}
1498
1499STDMETHODIMP Host::FindUSBDeviceByAddress(IN_BSTR aAddress,
1500 IHostUSBDevice **aDevice)
1501{
1502#ifdef VBOX_WITH_USB
1503 CheckComArgStrNotEmptyOrNull(aAddress);
1504 CheckComArgOutPointerValid(aDevice);
1505
1506 *aDevice = NULL;
1507
1508 SafeIfaceArray<IHostUSBDevice> devsvec;
1509 HRESULT rc = COMGETTER(USBDevices) (ComSafeArrayAsOutParam(devsvec));
1510 if (FAILED(rc)) return rc;
1511
1512 for (size_t i = 0; i < devsvec.size(); ++i)
1513 {
1514 Bstr address;
1515 rc = devsvec[i]->COMGETTER(Address) (address.asOutParam());
1516 if (FAILED(rc)) return rc;
1517 if (address == aAddress)
1518 {
1519 return ComObjPtr<IHostUSBDevice> (devsvec[i]).queryInterfaceTo(aDevice);
1520 }
1521 }
1522
1523 return setErrorNoLog(VBOX_E_OBJECT_NOT_FOUND,
1524 tr("Could not find a USB device with address '%ls'"),
1525 aAddress);
1526
1527#else /* !VBOX_WITH_USB */
1528 NOREF(aAddress);
1529 NOREF(aDevice);
1530 return E_NOTIMPL;
1531#endif /* !VBOX_WITH_USB */
1532}
1533
1534STDMETHODIMP Host::FindUSBDeviceById(IN_BSTR aId,
1535 IHostUSBDevice **aDevice)
1536{
1537#ifdef VBOX_WITH_USB
1538 CheckComArgExpr(aId, Guid (aId).isEmpty() == false);
1539 CheckComArgOutPointerValid(aDevice);
1540
1541 *aDevice = NULL;
1542
1543 SafeIfaceArray<IHostUSBDevice> devsvec;
1544 HRESULT rc = COMGETTER(USBDevices) (ComSafeArrayAsOutParam(devsvec));
1545 if (FAILED(rc)) return rc;
1546
1547 for (size_t i = 0; i < devsvec.size(); ++i)
1548 {
1549 Bstr id;
1550 rc = devsvec[i]->COMGETTER(Id) (id.asOutParam());
1551 if (FAILED(rc)) return rc;
1552 if (id == aId)
1553 {
1554 return ComObjPtr<IHostUSBDevice> (devsvec[i]).queryInterfaceTo(aDevice);
1555 }
1556 }
1557
1558 return setErrorNoLog (VBOX_E_OBJECT_NOT_FOUND, tr (
1559 "Could not find a USB device with uuid {%RTuuid}"),
1560 Guid (aId).raw());
1561
1562#else /* !VBOX_WITH_USB */
1563 NOREF(aId);
1564 NOREF(aDevice);
1565 return E_NOTIMPL;
1566#endif /* !VBOX_WITH_USB */
1567}
1568
1569STDMETHODIMP Host::GenerateMACAddress(BSTR *aAddress)
1570{
1571 CheckComArgOutPointerValid(aAddress);
1572 // no locking required
1573 Utf8Str mac;
1574 generateMACAddress(mac);
1575 Bstr(mac).cloneTo(aAddress);
1576 return S_OK;
1577}
1578
1579// public methods only for internal purposes
1580////////////////////////////////////////////////////////////////////////////////
1581
1582HRESULT Host::loadSettings(const settings::Host &data)
1583{
1584 HRESULT rc = S_OK;
1585#ifdef VBOX_WITH_USB
1586 AutoCaller autoCaller(this);
1587 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1588
1589 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1590
1591 for (settings::USBDeviceFiltersList::const_iterator it = data.llUSBDeviceFilters.begin();
1592 it != data.llUSBDeviceFilters.end();
1593 ++it)
1594 {
1595 const settings::USBDeviceFilter &f = *it;
1596 ComObjPtr<HostUSBDeviceFilter> pFilter;
1597 pFilter.createObject();
1598 rc = pFilter->init(this, f);
1599 if (FAILED(rc)) break;
1600
1601 m->llUSBDeviceFilters.push_back(pFilter);
1602 pFilter->mInList = true;
1603
1604 /* notify the proxy (only when the filter is active) */
1605 if (pFilter->getData().mActive)
1606 {
1607 HostUSBDeviceFilter *flt = pFilter; /* resolve ambiguity */
1608 flt->getId() = m->pUSBProxyService->insertFilter(&pFilter->getData().mUSBFilter);
1609 }
1610 }
1611#else
1612 NOREF(data);
1613#endif /* VBOX_WITH_USB */
1614 return rc;
1615}
1616
1617HRESULT Host::saveSettings(settings::Host &data)
1618{
1619#ifdef VBOX_WITH_USB
1620 AutoCaller autoCaller(this);
1621 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1622
1623 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1624
1625 data.llUSBDeviceFilters.clear();
1626
1627 for (USBDeviceFilterList::const_iterator it = m->llUSBDeviceFilters.begin();
1628 it != m->llUSBDeviceFilters.end();
1629 ++it)
1630 {
1631 ComObjPtr<HostUSBDeviceFilter> pFilter = *it;
1632 settings::USBDeviceFilter f;
1633 pFilter->saveSettings(f);
1634 data.llUSBDeviceFilters.push_back(f);
1635 }
1636#else
1637 NOREF(data);
1638#endif /* VBOX_WITH_USB */
1639
1640 return S_OK;
1641}
1642
1643/**
1644 * Sets the given pointer to point to the static list of DVD or floppy
1645 * drives in the Host instance data, depending on the @a mediumType
1646 * parameter.
1647 *
1648 * This builds the list on the first call; it adds or removes host drives
1649 * that may have changed if fRefresh == true.
1650 *
1651 * The caller must hold the medium tree write lock before calling this.
1652 * To protect the list to which the caller's pointer points, the caller
1653 * must also hold that lock.
1654 *
1655 * @param mediumType Must be DeviceType_Floppy or DeviceType_DVD.
1656 * @param fRefresh Whether to refresh the host drives list even if this is not the first call.
1657 * @param pll Caller's pointer which gets set to the static list of host drives.
1658 * @return
1659 */
1660HRESULT Host::getDrives(DeviceType_T mediumType,
1661 bool fRefresh,
1662 MediaList *&pll)
1663{
1664 HRESULT rc = S_OK;
1665 Assert(m->pParent->getMediaTreeLockHandle().isWriteLockOnCurrentThread());
1666
1667 MediaList llNew;
1668 MediaList *pllCached;
1669 bool *pfListBuilt = NULL;
1670
1671 switch (mediumType)
1672 {
1673 case DeviceType_DVD:
1674 if (!m->fDVDDrivesListBuilt || fRefresh)
1675 {
1676 rc = buildDVDDrivesList(llNew);
1677 if (FAILED(rc))
1678 return rc;
1679 pfListBuilt = &m->fDVDDrivesListBuilt;
1680 }
1681 pllCached = &m->llDVDDrives;
1682 break;
1683
1684 case DeviceType_Floppy:
1685 if (!m->fFloppyDrivesListBuilt || fRefresh)
1686 {
1687 rc = buildFloppyDrivesList(llNew);
1688 if (FAILED(rc))
1689 return rc;
1690 pfListBuilt = &m->fFloppyDrivesListBuilt;
1691 }
1692 pllCached = &m->llFloppyDrives;
1693 break;
1694
1695 default:
1696 return E_INVALIDARG;
1697 }
1698
1699 if (pfListBuilt)
1700 {
1701 // a list was built in llNew above:
1702 if (!*pfListBuilt)
1703 {
1704 // this was the first call (instance bool is still false): then just copy the whole list and return
1705 *pllCached = llNew;
1706 // and mark the instance data as "built"
1707 *pfListBuilt = true;
1708 }
1709 else
1710 {
1711 // list was built, and this was a subsequent call: then compare the old and the new lists
1712
1713 // remove drives from the cached list which are no longer present
1714 for (MediaList::iterator itCached = pllCached->begin();
1715 itCached != pllCached->end();
1716 /*nothing */)
1717 {
1718 Medium *pCached = *itCached;
1719 const Utf8Str strLocationCached = pCached->getLocationFull();
1720 bool fFound = false;
1721 for (MediaList::iterator itNew = llNew.begin();
1722 itNew != llNew.end();
1723 ++itNew)
1724 {
1725 Medium *pNew = *itNew;
1726 const Utf8Str strLocationNew = pNew->getLocationFull();
1727 if (strLocationNew == strLocationCached)
1728 {
1729 fFound = true;
1730 break;
1731 }
1732 }
1733 if (!fFound)
1734 itCached = pllCached->erase(itCached);
1735 else
1736 ++itCached;
1737 }
1738
1739 // add drives to the cached list that are not on there yet
1740 for (MediaList::iterator itNew = llNew.begin();
1741 itNew != llNew.end();
1742 ++itNew)
1743 {
1744 Medium *pNew = *itNew;
1745 const Utf8Str strLocationNew = pNew->getLocationFull();
1746 bool fFound = false;
1747 for (MediaList::iterator itCached = pllCached->begin();
1748 itCached != pllCached->end();
1749 ++itCached)
1750 {
1751 Medium *pCached = *itCached;
1752 const Utf8Str strLocationCached = pCached->getLocationFull();
1753 if (strLocationNew == strLocationCached)
1754 {
1755 fFound = true;
1756 break;
1757 }
1758 }
1759
1760 if (!fFound)
1761 pllCached->push_back(pNew);
1762 }
1763 }
1764 }
1765
1766 // return cached list to caller
1767 pll = pllCached;
1768
1769 return rc;
1770}
1771
1772/**
1773 * Goes through the list of host drives that would be returned by getDrives()
1774 * and looks for a host drive with the given UUID. If found, it sets pMedium
1775 * to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
1776 *
1777 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
1778 * @param uuid Medium UUID of host drive to look for.
1779 * @param fRefresh Whether to refresh the host drives list (see getDrives())
1780 * @param pMedium Medium object, if found…
1781 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
1782 */
1783HRESULT Host::findHostDriveById(DeviceType_T mediumType,
1784 const Guid &uuid,
1785 bool fRefresh,
1786 ComObjPtr<Medium> &pMedium)
1787{
1788 MediaList *pllMedia;
1789
1790 AutoWriteLock wlock(m->pParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
1791 HRESULT rc = getDrives(mediumType, fRefresh, pllMedia);
1792 if (SUCCEEDED(rc))
1793 {
1794 for (MediaList::iterator it = pllMedia->begin();
1795 it != pllMedia->end();
1796 ++it)
1797 {
1798 Medium *pThis = *it;
1799 AutoCaller mediumCaller(pThis);
1800 AutoReadLock mediumLock(pThis COMMA_LOCKVAL_SRC_POS);
1801 if (pThis->getId() == uuid)
1802 {
1803 pMedium = pThis;
1804 return S_OK;
1805 }
1806 }
1807 }
1808
1809 return VBOX_E_OBJECT_NOT_FOUND;
1810}
1811
1812/**
1813 * Goes through the list of host drives that would be returned by getDrives()
1814 * and looks for a host drive with the given name. If found, it sets pMedium
1815 * to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
1816 *
1817 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
1818 * @param strLocationFull Name (path) of host drive to look for.
1819 * @param fRefresh Whether to refresh the host drives list (see getDrives())
1820 * @param pMedium Medium object, if found…
1821 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
1822 */
1823HRESULT Host::findHostDriveByName(DeviceType_T mediumType,
1824 const Utf8Str &strLocationFull,
1825 bool fRefresh,
1826 ComObjPtr<Medium> &pMedium)
1827{
1828 MediaList *pllMedia;
1829
1830 AutoWriteLock wlock(m->pParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
1831 HRESULT rc = getDrives(mediumType, fRefresh, pllMedia);
1832 if (SUCCEEDED(rc))
1833 {
1834 for (MediaList::iterator it = pllMedia->begin();
1835 it != pllMedia->end();
1836 ++it)
1837 {
1838 Medium *pThis = *it;
1839 AutoCaller mediumCaller(pThis);
1840 AutoReadLock mediumLock(pThis COMMA_LOCKVAL_SRC_POS);
1841 if (pThis->getLocationFull() == strLocationFull)
1842 {
1843 pMedium = pThis;
1844 return S_OK;
1845 }
1846 }
1847 }
1848
1849 return VBOX_E_OBJECT_NOT_FOUND;
1850}
1851
1852/**
1853 * Goes through the list of host drives that would be returned by getDrives()
1854 * and looks for a host drive with the given name, location or ID. If found,
1855 * it sets pMedium to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
1856 *
1857 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
1858 * @param strNameOrId Name or full location or UUID of host drive to look for.
1859 * @param pMedium Medium object, if found…
1860 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
1861 */
1862HRESULT Host::findHostDriveByNameOrId(DeviceType_T mediumType,
1863 const Utf8Str &strNameOrId,
1864 ComObjPtr<Medium> &pMedium)
1865{
1866 AutoWriteLock wlock(m->pParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
1867
1868 Guid uuid(strNameOrId);
1869 if (!uuid.isEmpty())
1870 return findHostDriveById(mediumType, uuid, true /* fRefresh */, pMedium);
1871
1872 // string is not a syntactically valid UUID: try a name then
1873 return findHostDriveByName(mediumType, strNameOrId, true /* fRefresh */, pMedium);
1874}
1875
1876/**
1877 * Called from getDrives() to build the DVD drives list.
1878 * @param pll
1879 * @return
1880 */
1881HRESULT Host::buildDVDDrivesList(MediaList &list)
1882{
1883 HRESULT rc = S_OK;
1884
1885 Assert(m->pParent->getMediaTreeLockHandle().isWriteLockOnCurrentThread());
1886
1887 try
1888 {
1889#if defined(RT_OS_WINDOWS)
1890 int sz = GetLogicalDriveStrings(0, NULL);
1891 TCHAR *hostDrives = new TCHAR[sz+1];
1892 GetLogicalDriveStrings(sz, hostDrives);
1893 wchar_t driveName[3] = { '?', ':', '\0' };
1894 TCHAR *p = hostDrives;
1895 do
1896 {
1897 if (GetDriveType(p) == DRIVE_CDROM)
1898 {
1899 driveName[0] = *p;
1900 ComObjPtr<Medium> hostDVDDriveObj;
1901 hostDVDDriveObj.createObject();
1902 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(driveName));
1903 list.push_back(hostDVDDriveObj);
1904 }
1905 p += _tcslen(p) + 1;
1906 }
1907 while (*p);
1908 delete[] hostDrives;
1909
1910#elif defined(RT_OS_SOLARIS)
1911# ifdef VBOX_USE_LIBHAL
1912 if (!getDVDInfoFromHal(list))
1913# endif
1914 {
1915 getDVDInfoFromDevTree(list);
1916 }
1917
1918#elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
1919 if (RT_SUCCESS(m->hostDrives.updateDVDs()))
1920 for (DriveInfoList::const_iterator it = m->hostDrives.DVDBegin();
1921 SUCCEEDED(rc) && it != m->hostDrives.DVDEnd(); ++it)
1922 {
1923 ComObjPtr<Medium> hostDVDDriveObj;
1924 Utf8Str location(it->mDevice);
1925 Utf8Str description(it->mDescription);
1926 if (SUCCEEDED(rc))
1927 rc = hostDVDDriveObj.createObject();
1928 if (SUCCEEDED(rc))
1929 rc = hostDVDDriveObj->init(m->pParent, DeviceType_DVD, location, description);
1930 if (SUCCEEDED(rc))
1931 list.push_back(hostDVDDriveObj);
1932 }
1933#elif defined(RT_OS_DARWIN)
1934 PDARWINDVD cur = DarwinGetDVDDrives();
1935 while (cur)
1936 {
1937 ComObjPtr<Medium> hostDVDDriveObj;
1938 hostDVDDriveObj.createObject();
1939 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(cur->szName));
1940 list.push_back(hostDVDDriveObj);
1941
1942 /* next */
1943 void *freeMe = cur;
1944 cur = cur->pNext;
1945 RTMemFree(freeMe);
1946 }
1947#else
1948 /* PORTME */
1949#endif
1950 }
1951 catch(std::bad_alloc &)
1952 {
1953 rc = E_OUTOFMEMORY;
1954 }
1955 return rc;
1956}
1957
1958/**
1959 * Called from getDrives() to build the floppy drives list.
1960 * @param list
1961 * @return
1962 */
1963HRESULT Host::buildFloppyDrivesList(MediaList &list)
1964{
1965 HRESULT rc = S_OK;
1966
1967 Assert(m->pParent->getMediaTreeLockHandle().isWriteLockOnCurrentThread());
1968
1969 try
1970 {
1971#ifdef RT_OS_WINDOWS
1972 int sz = GetLogicalDriveStrings(0, NULL);
1973 TCHAR *hostDrives = new TCHAR[sz+1];
1974 GetLogicalDriveStrings(sz, hostDrives);
1975 wchar_t driveName[3] = { '?', ':', '\0' };
1976 TCHAR *p = hostDrives;
1977 do
1978 {
1979 if (GetDriveType(p) == DRIVE_REMOVABLE)
1980 {
1981 driveName[0] = *p;
1982 ComObjPtr<Medium> hostFloppyDriveObj;
1983 hostFloppyDriveObj.createObject();
1984 hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, Bstr(driveName));
1985 list.push_back(hostFloppyDriveObj);
1986 }
1987 p += _tcslen(p) + 1;
1988 }
1989 while (*p);
1990 delete[] hostDrives;
1991#elif defined(RT_OS_LINUX)
1992 if (RT_SUCCESS(m->hostDrives.updateFloppies()))
1993 for (DriveInfoList::const_iterator it = m->hostDrives.FloppyBegin();
1994 SUCCEEDED(rc) && it != m->hostDrives.FloppyEnd(); ++it)
1995 {
1996 ComObjPtr<Medium> hostFloppyDriveObj;
1997 Utf8Str location(it->mDevice);
1998 Utf8Str description(it->mDescription);
1999 if (SUCCEEDED(rc))
2000 rc = hostFloppyDriveObj.createObject();
2001 if (SUCCEEDED(rc))
2002 rc = hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, location, description);
2003 if (SUCCEEDED(rc))
2004 list.push_back(hostFloppyDriveObj);
2005 }
2006#else
2007 NOREF(list);
2008 /* PORTME */
2009#endif
2010 }
2011 catch(std::bad_alloc &)
2012 {
2013 rc = E_OUTOFMEMORY;
2014 }
2015
2016 return rc;
2017}
2018
2019#ifdef VBOX_WITH_USB
2020USBProxyService* Host::usbProxyService()
2021{
2022 return m->pUSBProxyService;
2023}
2024
2025HRESULT Host::addChild(HostUSBDeviceFilter *pChild)
2026{
2027 AutoCaller autoCaller(this);
2028 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2029
2030 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2031
2032 m->llChildren.push_back(pChild);
2033
2034 return S_OK;
2035}
2036
2037HRESULT Host::removeChild(HostUSBDeviceFilter *pChild)
2038{
2039 AutoCaller autoCaller(this);
2040 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2041
2042 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2043
2044 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
2045 it != m->llChildren.end();
2046 ++it)
2047 {
2048 if (*it == pChild)
2049 {
2050 m->llChildren.erase(it);
2051 break;
2052 }
2053 }
2054
2055 return S_OK;
2056}
2057
2058VirtualBox* Host::parent()
2059{
2060 return m->pParent;
2061}
2062
2063/**
2064 * Called by setter methods of all USB device filters.
2065 */
2066HRESULT Host::onUSBDeviceFilterChange(HostUSBDeviceFilter *aFilter,
2067 BOOL aActiveChanged /* = FALSE */)
2068{
2069 AutoCaller autoCaller(this);
2070 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2071
2072 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2073
2074 if (aFilter->mInList)
2075 {
2076 if (aActiveChanged)
2077 {
2078 // insert/remove the filter from the proxy
2079 if (aFilter->getData().mActive)
2080 {
2081 ComAssertRet(aFilter->getId() == NULL, E_FAIL);
2082 aFilter->getId() = m->pUSBProxyService->insertFilter(&aFilter->getData().mUSBFilter);
2083 }
2084 else
2085 {
2086 ComAssertRet(aFilter->getId() != NULL, E_FAIL);
2087 m->pUSBProxyService->removeFilter(aFilter->getId());
2088 aFilter->getId() = NULL;
2089 }
2090 }
2091 else
2092 {
2093 if (aFilter->getData().mActive)
2094 {
2095 // update the filter in the proxy
2096 ComAssertRet(aFilter->getId() != NULL, E_FAIL);
2097 m->pUSBProxyService->removeFilter(aFilter->getId());
2098 aFilter->getId() = m->pUSBProxyService->insertFilter(&aFilter->getData().mUSBFilter);
2099 }
2100 }
2101
2102 // save the global settings... yeah, on every single filter property change
2103 // for that we should hold only the VirtualBox lock
2104 alock.release();
2105 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
2106 return m->pParent->saveSettings();
2107 }
2108
2109 return S_OK;
2110}
2111
2112
2113/**
2114 * Interface for obtaining a copy of the USBDeviceFilterList,
2115 * used by the USBProxyService.
2116 *
2117 * @param aGlobalFilters Where to put the global filter list copy.
2118 * @param aMachines Where to put the machine vector.
2119 */
2120void Host::getUSBFilters(Host::USBDeviceFilterList *aGlobalFilters)
2121{
2122 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2123
2124 *aGlobalFilters = m->llUSBDeviceFilters;
2125}
2126
2127#endif /* VBOX_WITH_USB */
2128
2129// private methods
2130////////////////////////////////////////////////////////////////////////////////
2131
2132#if defined(RT_OS_SOLARIS) && defined(VBOX_USE_LIBHAL)
2133
2134/**
2135 * Helper function to get the slice number from a device path
2136 *
2137 * @param pszDevLinkPath Pointer to a device path (/dev/(r)dsk/c7d1t0d0s3 etc.)
2138 * @returns Pointer to the slice portion of the given path.
2139 */
2140static char *solarisGetSliceFromPath(const char *pszDevLinkPath)
2141{
2142 char *pszFound = NULL;
2143 char *pszSlice = strrchr(pszDevLinkPath, 's');
2144 char *pszDisk = strrchr(pszDevLinkPath, 'd');
2145 if (pszSlice && pszSlice > pszDisk)
2146 pszFound = pszSlice;
2147 else
2148 pszFound = pszDisk;
2149
2150 if (pszFound && RT_C_IS_DIGIT(pszFound[1]))
2151 return pszFound;
2152
2153 return NULL;
2154}
2155
2156/**
2157 * Walk device links and returns an allocated path for the first one in the snapshot.
2158 *
2159 * @param DevLink Handle to the device link being walked.
2160 * @param pvArg Opaque data containing the pointer to the path.
2161 * @returns Pointer to an allocated device path string.
2162 */
2163static int solarisWalkDevLink(di_devlink_t DevLink, void *pvArg)
2164{
2165 char **ppszPath = (char **)pvArg;
2166 *ppszPath = strdup(di_devlink_path(DevLink));
2167 return DI_WALK_TERMINATE;
2168}
2169
2170/**
2171 * Walk all devices in the system and enumerate CD/DVD drives.
2172 * @param Node Handle to the current node.
2173 * @param pvArg Opaque data (holds list pointer).
2174 * @returns Solaris specific code whether to continue walking or not.
2175 */
2176static int solarisWalkDeviceNodeForDVD(di_node_t Node, void *pvArg)
2177{
2178 PSOLARISDVD *ppDrives = (PSOLARISDVD *)pvArg;
2179
2180 /*
2181 * Check for "removable-media" or "hotpluggable" instead of "SCSI" so that we also include USB CD-ROMs.
2182 * As unfortunately the Solaris drivers only export these common properties.
2183 */
2184 int *pInt = NULL;
2185 if ( di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "removable-media", &pInt) >= 0
2186 || di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "hotpluggable", &pInt) >= 0)
2187 {
2188 if (di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "inquiry-device-type", &pInt) > 0
2189 && ( *pInt == DTYPE_RODIRECT /* CDROM */
2190 || *pInt == DTYPE_OPTICAL)) /* Optical Drive */
2191 {
2192 char *pszProduct = NULL;
2193 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-product-id", &pszProduct) > 0)
2194 {
2195 char *pszVendor = NULL;
2196 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-vendor-id", &pszVendor) > 0)
2197 {
2198 /*
2199 * Found a DVD drive, we need to scan the minor nodes to find the correct
2200 * slice that represents the whole drive. "s2" is always the whole drive for CD/DVDs.
2201 */
2202 int Major = di_driver_major(Node);
2203 di_minor_t Minor = DI_MINOR_NIL;
2204 di_devlink_handle_t DevLink = di_devlink_init(NULL /* name */, 0 /* flags */);
2205 if (DevLink)
2206 {
2207 while ((Minor = di_minor_next(Node, Minor)) != DI_MINOR_NIL)
2208 {
2209 dev_t Dev = di_minor_devt(Minor);
2210 if ( Major != (int)major(Dev)
2211 || di_minor_spectype(Minor) == S_IFBLK
2212 || di_minor_type(Minor) != DDM_MINOR)
2213 {
2214 continue;
2215 }
2216
2217 char *pszMinorPath = di_devfs_minor_path(Minor);
2218 if (!pszMinorPath)
2219 continue;
2220
2221 char *pszDevLinkPath = NULL;
2222 di_devlink_walk(DevLink, NULL, pszMinorPath, DI_PRIMARY_LINK, &pszDevLinkPath, solarisWalkDevLink);
2223 di_devfs_path_free(pszMinorPath);
2224
2225 if (pszDevLinkPath)
2226 {
2227 char *pszSlice = solarisGetSliceFromPath(pszDevLinkPath);
2228 if ( pszSlice && !strcmp(pszSlice, "s2")
2229 && !strncmp(pszDevLinkPath, "/dev/rdsk", sizeof("/dev/rdsk") - 1)) /* We want only raw disks */
2230 {
2231 /*
2232 * We've got a fully qualified DVD drive. Add it to the list.
2233 */
2234 PSOLARISDVD pDrive = (PSOLARISDVD)RTMemAllocZ(sizeof(SOLARISDVD));
2235 if (RT_LIKELY(pDrive))
2236 {
2237 RTStrPrintf(pDrive->szDescription, sizeof(pDrive->szDescription), "%s %s", pszVendor, pszProduct);
2238 RTStrCopy(pDrive->szRawDiskPath, sizeof(pDrive->szRawDiskPath), pszDevLinkPath);
2239 if (*ppDrives)
2240 pDrive->pNext = *ppDrives;
2241 *ppDrives = pDrive;
2242
2243 /* We're not interested in any of the other slices, stop minor nodes traversal. */
2244 free(pszDevLinkPath);
2245 break;
2246 }
2247 }
2248 free(pszDevLinkPath);
2249 }
2250 }
2251 di_devlink_fini(&DevLink);
2252 }
2253 }
2254 }
2255 }
2256 }
2257 return DI_WALK_CONTINUE;
2258}
2259
2260/**
2261 * Solaris specific function to enumerate CD/DVD drives via the device tree.
2262 * Works on Solaris 10 as well as OpenSolaris without depending on libhal.
2263 */
2264void Host::getDVDInfoFromDevTree(std::list<ComObjPtr<Medium> > &list)
2265{
2266 PSOLARISDVD pDrives = NULL;
2267 di_node_t RootNode = di_init("/", DINFOCPYALL);
2268 if (RootNode != DI_NODE_NIL)
2269 di_walk_node(RootNode, DI_WALK_CLDFIRST, &pDrives, solarisWalkDeviceNodeForDVD);
2270
2271 di_fini(RootNode);
2272
2273 while (pDrives)
2274 {
2275 ComObjPtr<Medium> hostDVDDriveObj;
2276 hostDVDDriveObj.createObject();
2277 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(pDrives->szRawDiskPath), Bstr(pDrives->szDescription));
2278 list.push_back(hostDVDDriveObj);
2279
2280 void *pvDrive = pDrives;
2281 pDrives = pDrives->pNext;
2282 RTMemFree(pvDrive);
2283 }
2284}
2285
2286/* Solaris hosts, loading libhal at runtime */
2287
2288/**
2289 * Helper function to query the hal subsystem for information about DVD drives attached to the
2290 * system.
2291 *
2292 * @returns true if information was successfully obtained, false otherwise
2293 * @retval list drives found will be attached to this list
2294 */
2295bool Host::getDVDInfoFromHal(std::list<ComObjPtr<Medium> > &list)
2296{
2297 bool halSuccess = false;
2298 DBusError dbusError;
2299 if (!gLibHalCheckPresence())
2300 return false;
2301 gDBusErrorInit (&dbusError);
2302 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
2303 if (dbusConnection != 0)
2304 {
2305 LibHalContext *halContext = gLibHalCtxNew();
2306 if (halContext != 0)
2307 {
2308 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
2309 {
2310 if (gLibHalCtxInit(halContext, &dbusError))
2311 {
2312 int numDevices;
2313 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
2314 "storage.drive_type", "cdrom",
2315 &numDevices, &dbusError);
2316 if (halDevices != 0)
2317 {
2318 /* Hal is installed and working, so if no devices are reported, assume
2319 that there are none. */
2320 halSuccess = true;
2321 for (int i = 0; i < numDevices; i++)
2322 {
2323 char *devNode = gLibHalDeviceGetPropertyString(halContext,
2324 halDevices[i], "block.device", &dbusError);
2325#ifdef RT_OS_SOLARIS
2326 /* The CD/DVD ioctls work only for raw device nodes. */
2327 char *tmp = getfullrawname(devNode);
2328 gLibHalFreeString(devNode);
2329 devNode = tmp;
2330#endif
2331
2332 if (devNode != 0)
2333 {
2334// if (validateDevice(devNode, true))
2335// {
2336 Utf8Str description;
2337 char *vendor, *product;
2338 /* We do not check the error here, as this field may
2339 not even exist. */
2340 vendor = gLibHalDeviceGetPropertyString(halContext,
2341 halDevices[i], "info.vendor", 0);
2342 product = gLibHalDeviceGetPropertyString(halContext,
2343 halDevices[i], "info.product", &dbusError);
2344 if ((product != 0 && product[0] != 0))
2345 {
2346 if ((vendor != 0) && (vendor[0] != 0))
2347 {
2348 description = Utf8StrFmt ("%s %s",
2349 vendor, product);
2350 }
2351 else
2352 {
2353 description = product;
2354 }
2355 ComObjPtr<Medium> hostDVDDriveObj;
2356 hostDVDDriveObj.createObject();
2357 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
2358 Bstr(devNode), Bstr(description));
2359 list.push_back (hostDVDDriveObj);
2360 }
2361 else
2362 {
2363 if (product == 0)
2364 {
2365 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
2366 halDevices[i], dbusError.name, dbusError.message));
2367 gDBusErrorFree(&dbusError);
2368 }
2369 ComObjPtr<Medium> hostDVDDriveObj;
2370 hostDVDDriveObj.createObject();
2371 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
2372 Bstr(devNode));
2373 list.push_back (hostDVDDriveObj);
2374 }
2375 if (vendor != 0)
2376 {
2377 gLibHalFreeString(vendor);
2378 }
2379 if (product != 0)
2380 {
2381 gLibHalFreeString(product);
2382 }
2383// }
2384// else
2385// {
2386// LogRel(("Host::COMGETTER(DVDDrives): failed to validate the block device %s as a DVD drive\n"));
2387// }
2388#ifndef RT_OS_SOLARIS
2389 gLibHalFreeString(devNode);
2390#else
2391 free(devNode);
2392#endif
2393 }
2394 else
2395 {
2396 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
2397 halDevices[i], dbusError.name, dbusError.message));
2398 gDBusErrorFree(&dbusError);
2399 }
2400 }
2401 gLibHalFreeStringArray(halDevices);
2402 }
2403 else
2404 {
2405 LogRel(("Host::COMGETTER(DVDDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2406 gDBusErrorFree(&dbusError);
2407 }
2408 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
2409 {
2410 LogRel(("Host::COMGETTER(DVDDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2411 gDBusErrorFree(&dbusError);
2412 }
2413 }
2414 else
2415 {
2416 LogRel(("Host::COMGETTER(DVDDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2417 gDBusErrorFree(&dbusError);
2418 }
2419 gLibHalCtxFree(halContext);
2420 }
2421 else
2422 {
2423 LogRel(("Host::COMGETTER(DVDDrives): failed to set libhal connection to dbus.\n"));
2424 }
2425 }
2426 else
2427 {
2428 LogRel(("Host::COMGETTER(DVDDrives): failed to get a libhal context - out of memory?\n"));
2429 }
2430 gDBusConnectionUnref(dbusConnection);
2431 }
2432 else
2433 {
2434 LogRel(("Host::COMGETTER(DVDDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2435 gDBusErrorFree(&dbusError);
2436 }
2437 return halSuccess;
2438}
2439
2440
2441/**
2442 * Helper function to query the hal subsystem for information about floppy drives attached to the
2443 * system.
2444 *
2445 * @returns true if information was successfully obtained, false otherwise
2446 * @retval list drives found will be attached to this list
2447 */
2448bool Host::getFloppyInfoFromHal(std::list< ComObjPtr<Medium> > &list)
2449{
2450 bool halSuccess = false;
2451 DBusError dbusError;
2452 if (!gLibHalCheckPresence())
2453 return false;
2454 gDBusErrorInit (&dbusError);
2455 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
2456 if (dbusConnection != 0)
2457 {
2458 LibHalContext *halContext = gLibHalCtxNew();
2459 if (halContext != 0)
2460 {
2461 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
2462 {
2463 if (gLibHalCtxInit(halContext, &dbusError))
2464 {
2465 int numDevices;
2466 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
2467 "storage.drive_type", "floppy",
2468 &numDevices, &dbusError);
2469 if (halDevices != 0)
2470 {
2471 /* Hal is installed and working, so if no devices are reported, assume
2472 that there are none. */
2473 halSuccess = true;
2474 for (int i = 0; i < numDevices; i++)
2475 {
2476 char *driveType = gLibHalDeviceGetPropertyString(halContext,
2477 halDevices[i], "storage.drive_type", 0);
2478 if (driveType != 0)
2479 {
2480 if (strcmp(driveType, "floppy") != 0)
2481 {
2482 gLibHalFreeString(driveType);
2483 continue;
2484 }
2485 gLibHalFreeString(driveType);
2486 }
2487 else
2488 {
2489 /* An error occurred. The attribute "storage.drive_type"
2490 probably didn't exist. */
2491 continue;
2492 }
2493 char *devNode = gLibHalDeviceGetPropertyString(halContext,
2494 halDevices[i], "block.device", &dbusError);
2495 if (devNode != 0)
2496 {
2497// if (validateDevice(devNode, false))
2498// {
2499 Utf8Str description;
2500 char *vendor, *product;
2501 /* We do not check the error here, as this field may
2502 not even exist. */
2503 vendor = gLibHalDeviceGetPropertyString(halContext,
2504 halDevices[i], "info.vendor", 0);
2505 product = gLibHalDeviceGetPropertyString(halContext,
2506 halDevices[i], "info.product", &dbusError);
2507 if ((product != 0) && (product[0] != 0))
2508 {
2509 if ((vendor != 0) && (vendor[0] != 0))
2510 {
2511 description = Utf8StrFmt ("%s %s",
2512 vendor, product);
2513 }
2514 else
2515 {
2516 description = product;
2517 }
2518 ComObjPtr<Medium> hostFloppyDrive;
2519 hostFloppyDrive.createObject();
2520 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
2521 Bstr(devNode), Bstr(description));
2522 list.push_back (hostFloppyDrive);
2523 }
2524 else
2525 {
2526 if (product == 0)
2527 {
2528 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
2529 halDevices[i], dbusError.name, dbusError.message));
2530 gDBusErrorFree(&dbusError);
2531 }
2532 ComObjPtr<Medium> hostFloppyDrive;
2533 hostFloppyDrive.createObject();
2534 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
2535 Bstr(devNode));
2536 list.push_back (hostFloppyDrive);
2537 }
2538 if (vendor != 0)
2539 {
2540 gLibHalFreeString(vendor);
2541 }
2542 if (product != 0)
2543 {
2544 gLibHalFreeString(product);
2545 }
2546// }
2547// else
2548// {
2549// LogRel(("Host::COMGETTER(FloppyDrives): failed to validate the block device %s as a floppy drive\n"));
2550// }
2551 gLibHalFreeString(devNode);
2552 }
2553 else
2554 {
2555 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
2556 halDevices[i], dbusError.name, dbusError.message));
2557 gDBusErrorFree(&dbusError);
2558 }
2559 }
2560 gLibHalFreeStringArray(halDevices);
2561 }
2562 else
2563 {
2564 LogRel(("Host::COMGETTER(FloppyDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2565 gDBusErrorFree(&dbusError);
2566 }
2567 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
2568 {
2569 LogRel(("Host::COMGETTER(FloppyDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2570 gDBusErrorFree(&dbusError);
2571 }
2572 }
2573 else
2574 {
2575 LogRel(("Host::COMGETTER(FloppyDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2576 gDBusErrorFree(&dbusError);
2577 }
2578 gLibHalCtxFree(halContext);
2579 }
2580 else
2581 {
2582 LogRel(("Host::COMGETTER(FloppyDrives): failed to set libhal connection to dbus.\n"));
2583 }
2584 }
2585 else
2586 {
2587 LogRel(("Host::COMGETTER(FloppyDrives): failed to get a libhal context - out of memory?\n"));
2588 }
2589 gDBusConnectionUnref(dbusConnection);
2590 }
2591 else
2592 {
2593 LogRel(("Host::COMGETTER(FloppyDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2594 gDBusErrorFree(&dbusError);
2595 }
2596 return halSuccess;
2597}
2598#endif /* RT_OS_SOLARIS and VBOX_USE_HAL */
2599
2600/** @todo get rid of dead code below - RT_OS_SOLARIS and RT_OS_LINUX are never both set */
2601#if defined(RT_OS_SOLARIS)
2602
2603/**
2604 * Helper function to parse the given mount file and add found entries
2605 */
2606void Host::parseMountTable(char *mountTable, std::list< ComObjPtr<Medium> > &list)
2607{
2608#ifdef RT_OS_LINUX
2609 FILE *mtab = setmntent(mountTable, "r");
2610 if (mtab)
2611 {
2612 struct mntent *mntent;
2613 char *mnt_type;
2614 char *mnt_dev;
2615 char *tmp;
2616 while ((mntent = getmntent(mtab)))
2617 {
2618 mnt_type = (char*)malloc(strlen(mntent->mnt_type) + 1);
2619 mnt_dev = (char*)malloc(strlen(mntent->mnt_fsname) + 1);
2620 strcpy(mnt_type, mntent->mnt_type);
2621 strcpy(mnt_dev, mntent->mnt_fsname);
2622 // supermount fs case
2623 if (strcmp(mnt_type, "supermount") == 0)
2624 {
2625 tmp = strstr(mntent->mnt_opts, "fs=");
2626 if (tmp)
2627 {
2628 free(mnt_type);
2629 mnt_type = strdup(tmp + strlen("fs="));
2630 if (mnt_type)
2631 {
2632 tmp = strchr(mnt_type, ',');
2633 if (tmp)
2634 *tmp = '\0';
2635 }
2636 }
2637 tmp = strstr(mntent->mnt_opts, "dev=");
2638 if (tmp)
2639 {
2640 free(mnt_dev);
2641 mnt_dev = strdup(tmp + strlen("dev="));
2642 if (mnt_dev)
2643 {
2644 tmp = strchr(mnt_dev, ',');
2645 if (tmp)
2646 *tmp = '\0';
2647 }
2648 }
2649 }
2650 // use strstr here to cover things fs types like "udf,iso9660"
2651 if (strstr(mnt_type, "iso9660") == 0)
2652 {
2653 /** @todo check whether we've already got the drive in our list! */
2654 if (validateDevice(mnt_dev, true))
2655 {
2656 ComObjPtr<Medium> hostDVDDriveObj;
2657 hostDVDDriveObj.createObject();
2658 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(mnt_dev));
2659 list.push_back (hostDVDDriveObj);
2660 }
2661 }
2662 free(mnt_dev);
2663 free(mnt_type);
2664 }
2665 endmntent(mtab);
2666 }
2667#else // RT_OS_SOLARIS
2668 FILE *mntFile = fopen(mountTable, "r");
2669 if (mntFile)
2670 {
2671 struct mnttab mntTab;
2672 while (getmntent(mntFile, &mntTab) == 0)
2673 {
2674 const char *mountName = mntTab.mnt_special;
2675 const char *mountPoint = mntTab.mnt_mountp;
2676 const char *mountFSType = mntTab.mnt_fstype;
2677 if (mountName && mountPoint && mountFSType)
2678 {
2679 // skip devices we are not interested in
2680 if ((*mountName && mountName[0] == '/') && // skip 'fake' devices (like -hosts, proc, fd, swap)
2681 (*mountFSType && (strncmp(mountFSType, "devfs", 5) != 0 && // skip devfs (i.e. /devices)
2682 strncmp(mountFSType, "dev", 3) != 0 && // skip dev (i.e. /dev)
2683 strncmp(mountFSType, "lofs", 4) != 0))) // skip loop-back file-system (lofs)
2684 {
2685 char *rawDevName = getfullrawname((char *)mountName);
2686 if (validateDevice(rawDevName, true))
2687 {
2688 ComObjPtr<Medium> hostDVDDriveObj;
2689 hostDVDDriveObj.createObject();
2690 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(rawDevName));
2691 list.push_back (hostDVDDriveObj);
2692 }
2693 free(rawDevName);
2694 }
2695 }
2696 }
2697
2698 fclose(mntFile);
2699 }
2700#endif
2701}
2702
2703/**
2704 * Helper function to check whether the given device node is a valid drive
2705 */
2706bool Host::validateDevice(const char *deviceNode, bool isCDROM)
2707{
2708 struct stat statInfo;
2709 bool retValue = false;
2710
2711 // sanity check
2712 if (!deviceNode)
2713 {
2714 return false;
2715 }
2716
2717 // first a simple stat() call
2718 if (stat(deviceNode, &statInfo) < 0)
2719 {
2720 return false;
2721 }
2722 else
2723 {
2724 if (isCDROM)
2725 {
2726 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2727 {
2728 int fileHandle;
2729 // now try to open the device
2730 fileHandle = open(deviceNode, O_RDONLY | O_NONBLOCK, 0);
2731 if (fileHandle >= 0)
2732 {
2733 cdrom_subchnl cdChannelInfo;
2734 cdChannelInfo.cdsc_format = CDROM_MSF;
2735 // this call will finally reveal the whole truth
2736#ifdef RT_OS_LINUX
2737 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2738 (errno == EIO) || (errno == ENOENT) ||
2739 (errno == EINVAL) || (errno == ENOMEDIUM))
2740#else
2741 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2742 (errno == EIO) || (errno == ENOENT) ||
2743 (errno == EINVAL))
2744#endif
2745 {
2746 retValue = true;
2747 }
2748 close(fileHandle);
2749 }
2750 }
2751 } else
2752 {
2753 // floppy case
2754 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2755 {
2756 /// @todo do some more testing, maybe a nice IOCTL!
2757 retValue = true;
2758 }
2759 }
2760 }
2761 return retValue;
2762}
2763#endif // RT_OS_SOLARIS
2764
2765#ifdef VBOX_WITH_USB
2766/**
2767 * Checks for the presence and status of the USB Proxy Service.
2768 * Returns S_OK when the Proxy is present and OK, VBOX_E_HOST_ERROR (as a
2769 * warning) if the proxy service is not available due to the way the host is
2770 * configured (at present, that means that usbfs and hal/DBus are not
2771 * available on a Linux host) or E_FAIL and a corresponding error message
2772 * otherwise. Intended to be used by methods that rely on the Proxy Service
2773 * availability.
2774 *
2775 * @note This method may return a warning result code. It is recommended to use
2776 * MultiError to store the return value.
2777 *
2778 * @note Locks this object for reading.
2779 */
2780HRESULT Host::checkUSBProxyService()
2781{
2782 AutoCaller autoCaller(this);
2783 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2784
2785 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2786
2787 AssertReturn(m->pUSBProxyService, E_FAIL);
2788 if (!m->pUSBProxyService->isActive())
2789 {
2790 /* disable the USB controller completely to avoid assertions if the
2791 * USB proxy service could not start. */
2792
2793 switch (m->pUSBProxyService->getLastError())
2794 {
2795 case VERR_FILE_NOT_FOUND: /** @todo what does this mean? */
2796 return setWarning(E_FAIL,
2797 tr("Could not load the Host USB Proxy Service (VERR_FILE_NOT_FOUND). The service might not be installed on the host computer"));
2798 case VERR_VUSB_USB_DEVICE_PERMISSION:
2799 return setWarning(E_FAIL,
2800 tr("VirtualBox is not currently allowed to access USB devices. You can change this by adding your user to the 'vboxusers' group. Please see the user manual for a more detailed explanation"));
2801 case VERR_VUSB_USBFS_PERMISSION:
2802 return setWarning(E_FAIL,
2803 tr("VirtualBox is not currently allowed to access USB devices. You can change this by allowing your user to access the 'usbfs' folder and files. Please see the user manual for a more detailed explanation"));
2804 case VINF_SUCCESS:
2805 return setWarning(E_FAIL,
2806 tr("The USB Proxy Service has not yet been ported to this host"));
2807 default:
2808 return setWarning (E_FAIL, "%s: %Rrc",
2809 tr ("Could not load the Host USB Proxy service"),
2810 m->pUSBProxyService->getLastError());
2811 }
2812 }
2813
2814 return S_OK;
2815}
2816#endif /* VBOX_WITH_USB */
2817
2818HRESULT Host::updateNetIfList()
2819{
2820#ifdef VBOX_WITH_HOSTNETIF_API
2821 AssertReturn(AutoCaller(this).state() == InInit ||
2822 isWriteLockOnCurrentThread(), E_FAIL);
2823
2824 HostNetworkInterfaceList list, listCopy;
2825 int rc = NetIfList(list);
2826 if (rc)
2827 {
2828 Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
2829 return E_FAIL;
2830 }
2831 AssertReturn(m->pParent, E_FAIL);
2832 /* Make a copy as the original may be partially destroyed later. */
2833 listCopy = list;
2834 HostNetworkInterfaceList::iterator itOld, itNew;
2835 PerformanceCollector *aCollector = m->pParent->performanceCollector();
2836 for (itOld = m->llNetIfs.begin(); itOld != m->llNetIfs.end(); ++itOld)
2837 {
2838 bool fGone = true;
2839 Bstr nameOld;
2840 (*itOld)->COMGETTER(Name) (nameOld.asOutParam());
2841 for (itNew = listCopy.begin(); itNew != listCopy.end(); ++itNew)
2842 {
2843 Bstr nameNew;
2844 (*itNew)->COMGETTER(Name) (nameNew.asOutParam());
2845 if (nameNew == nameOld)
2846 {
2847 fGone = false;
2848 listCopy.erase(itNew);
2849 break;
2850 }
2851 }
2852 if (fGone)
2853 (*itOld)->unregisterMetrics(aCollector, this);
2854 }
2855 /* At this point listCopy will contain newly discovered interfaces only. */
2856 for (itNew = listCopy.begin(); itNew != listCopy.end(); ++itNew)
2857 {
2858 (*itNew)->setVirtualBox(m->pParent);
2859 (*itNew)->registerMetrics(aCollector, this);
2860 }
2861 m->llNetIfs = list;
2862 return S_OK;
2863#else
2864 return E_NOTIMPL;
2865#endif
2866}
2867
2868#ifdef VBOX_WITH_RESOURCE_USAGE_API
2869
2870void Host::registerMetrics(PerformanceCollector *aCollector)
2871{
2872 pm::CollectorHAL *hal = aCollector->getHAL();
2873 /* Create sub metrics */
2874 pm::SubMetric *cpuLoadUser = new pm::SubMetric("CPU/Load/User",
2875 "Percentage of processor time spent in user mode.");
2876 pm::SubMetric *cpuLoadKernel = new pm::SubMetric("CPU/Load/Kernel",
2877 "Percentage of processor time spent in kernel mode.");
2878 pm::SubMetric *cpuLoadIdle = new pm::SubMetric("CPU/Load/Idle",
2879 "Percentage of processor time spent idling.");
2880 pm::SubMetric *cpuMhzSM = new pm::SubMetric("CPU/MHz",
2881 "Average of current frequency of all processors.");
2882 pm::SubMetric *ramUsageTotal = new pm::SubMetric("RAM/Usage/Total",
2883 "Total physical memory installed.");
2884 pm::SubMetric *ramUsageUsed = new pm::SubMetric("RAM/Usage/Used",
2885 "Physical memory currently occupied.");
2886 pm::SubMetric *ramUsageFree = new pm::SubMetric("RAM/Usage/Free",
2887 "Physical memory currently available to applications.");
2888 pm::SubMetric *ramVMMUsed = new pm::SubMetric("RAM/VMM/Used",
2889 "Total physical memory used by the hypervisor.");
2890 pm::SubMetric *ramVMMFree = new pm::SubMetric("RAM/VMM/Free",
2891 "Total physical memory free inside the hypervisor.");
2892 pm::SubMetric *ramVMMBallooned = new pm::SubMetric("RAM/VMM/Ballooned",
2893 "Total physical memory ballooned by the hypervisor.");
2894 pm::SubMetric *ramVMMShared = new pm::SubMetric("RAM/VMM/Shared",
2895 "Total physical memory shared between VMs.");
2896
2897
2898 /* Create and register base metrics */
2899 pm::BaseMetric *cpuLoad = new pm::HostCpuLoadRaw(hal, this, cpuLoadUser, cpuLoadKernel,
2900 cpuLoadIdle);
2901 aCollector->registerBaseMetric (cpuLoad);
2902 pm::BaseMetric *cpuMhz = new pm::HostCpuMhz(hal, this, cpuMhzSM);
2903 aCollector->registerBaseMetric (cpuMhz);
2904 pm::BaseMetric *ramUsage = new pm::HostRamUsage(hal, this,
2905 ramUsageTotal,
2906 ramUsageUsed,
2907 ramUsageFree);
2908 aCollector->registerBaseMetric (ramUsage);
2909 pm::BaseMetric *ramVmm = new pm::HostRamVmm(aCollector->getGuestManager(), this,
2910 ramVMMUsed,
2911 ramVMMFree,
2912 ramVMMBallooned,
2913 ramVMMShared);
2914 aCollector->registerBaseMetric (ramVmm);
2915
2916 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser, 0));
2917 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
2918 new pm::AggregateAvg()));
2919 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
2920 new pm::AggregateMin()));
2921 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
2922 new pm::AggregateMax()));
2923
2924 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel, 0));
2925 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
2926 new pm::AggregateAvg()));
2927 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
2928 new pm::AggregateMin()));
2929 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
2930 new pm::AggregateMax()));
2931
2932 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle, 0));
2933 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
2934 new pm::AggregateAvg()));
2935 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
2936 new pm::AggregateMin()));
2937 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
2938 new pm::AggregateMax()));
2939
2940 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM, 0));
2941 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
2942 new pm::AggregateAvg()));
2943 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
2944 new pm::AggregateMin()));
2945 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
2946 new pm::AggregateMax()));
2947
2948 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal, 0));
2949 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
2950 new pm::AggregateAvg()));
2951 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
2952 new pm::AggregateMin()));
2953 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
2954 new pm::AggregateMax()));
2955
2956 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed, 0));
2957 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
2958 new pm::AggregateAvg()));
2959 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
2960 new pm::AggregateMin()));
2961 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
2962 new pm::AggregateMax()));
2963
2964 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree, 0));
2965 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
2966 new pm::AggregateAvg()));
2967 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
2968 new pm::AggregateMin()));
2969 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
2970 new pm::AggregateMax()));
2971
2972 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed, 0));
2973 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
2974 new pm::AggregateAvg()));
2975 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
2976 new pm::AggregateMin()));
2977 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
2978 new pm::AggregateMax()));
2979
2980 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree, 0));
2981 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
2982 new pm::AggregateAvg()));
2983 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
2984 new pm::AggregateMin()));
2985 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
2986 new pm::AggregateMax()));
2987
2988 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned, 0));
2989 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
2990 new pm::AggregateAvg()));
2991 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
2992 new pm::AggregateMin()));
2993 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
2994 new pm::AggregateMax()));
2995
2996 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared, 0));
2997 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
2998 new pm::AggregateAvg()));
2999 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
3000 new pm::AggregateMin()));
3001 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
3002 new pm::AggregateMax()));
3003}
3004
3005void Host::unregisterMetrics (PerformanceCollector *aCollector)
3006{
3007 aCollector->unregisterMetricsFor(this);
3008 aCollector->unregisterBaseMetricsFor(this);
3009}
3010
3011
3012/* static */
3013void Host::generateMACAddress(Utf8Str &mac)
3014{
3015 /*
3016 * Our strategy is as follows: the first three bytes are our fixed
3017 * vendor ID (080027). The remaining 3 bytes will be taken from the
3018 * start of a GUID. This is a fairly safe algorithm.
3019 */
3020 Guid guid;
3021 guid.create();
3022 mac = Utf8StrFmt("080027%02X%02X%02X",
3023 guid.raw()->au8[0], guid.raw()->au8[1], guid.raw()->au8[2]);
3024}
3025
3026#endif /* VBOX_WITH_RESOURCE_USAGE_API */
3027
3028/* 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