VirtualBox

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

Last change on this file since 40755 was 40755, checked in by vboxsync, 13 years ago

Main/HostImpl: fixed r76982 (the old santiy check was wrong and prevented to create host interfaces)

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette