VirtualBox

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

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

Main/Host: must use the normal medium tree lock, as the Medium objects use this one implicitly in the uninit method which is used on destruction.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 102.5 KB
Line 
1/* $Id: HostImpl.cpp 40183 2012-02-20 15:27:25Z 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.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
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 !defined(RT_OS_WINDOWS)
1105 Bstr tmpAddr, tmpMask, tmpName;
1106 HRESULT hrc;
1107 hrc = (*aHostNetworkInterface)->COMGETTER(Name)(tmpName.asOutParam());
1108 ComAssertComRCRet(hrc, hrc);
1109 hrc = (*aHostNetworkInterface)->COMGETTER(IPAddress)(tmpAddr.asOutParam());
1110 ComAssertComRCRet(hrc, hrc);
1111 hrc = (*aHostNetworkInterface)->COMGETTER(NetworkMask)(tmpMask.asOutParam());
1112 ComAssertComRCRet(hrc, hrc);
1113 /*
1114 * We need to write the default IP address and mask to extra data now,
1115 * so the interface gets re-created after vboxnetadp.ko reload.
1116 * Note that we avoid calling EnableStaticIpConfig since it would
1117 * change the address on host's interface as well and we want to
1118 * postpone the change until VM actually starts.
1119 */
1120 hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPAddress",
1121 tmpName.raw()).raw(),
1122 tmpAddr.raw());
1123 ComAssertComRCRet(hrc, hrc);
1124
1125 hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPNetMask",
1126 tmpName.raw()).raw(),
1127 tmpMask.raw());
1128 ComAssertComRCRet(hrc, hrc);
1129#endif
1130 return S_OK;
1131 }
1132
1133 return r == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
1134#else
1135 return E_NOTIMPL;
1136#endif
1137}
1138
1139STDMETHODIMP Host::RemoveHostOnlyNetworkInterface(IN_BSTR aId,
1140 IProgress **aProgress)
1141{
1142 CheckComArgOutPointerValid(aProgress);
1143
1144 AutoCaller autoCaller(this);
1145 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1146
1147#ifdef VBOX_WITH_HOSTNETIF_API
1148 /* No need to lock anything, the code below does not touch the state
1149 * of the host object. If that ever changes then check for lock order
1150 * violations with the called functions. */
1151
1152 Bstr name;
1153 HRESULT rc;
1154
1155 /* first check whether an interface with the given name already exists */
1156 {
1157 ComPtr<IHostNetworkInterface> iface;
1158 if (FAILED(FindHostNetworkInterfaceById(aId,
1159 iface.asOutParam())))
1160 return setError(VBOX_E_OBJECT_NOT_FOUND,
1161 tr("Host network interface with UUID {%RTuuid} does not exist"),
1162 Guid (aId).raw());
1163 rc = iface->COMGETTER(Name)(name.asOutParam());
1164 ComAssertComRCRet(rc, rc);
1165 }
1166
1167 int r = NetIfRemoveHostOnlyNetworkInterface(m->pParent, Guid(aId).ref(), aProgress);
1168 if (RT_SUCCESS(r))
1169 {
1170 /* Drop configuration parameters for removed interface */
1171 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPAddress", name.raw()).raw(), NULL);
1172 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPNetMask", name.raw()).raw(), NULL);
1173 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPV6Address", name.raw()).raw(), NULL);
1174 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPV6NetMask", name.raw()).raw(), NULL);
1175
1176 return S_OK;
1177 }
1178
1179 return r == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
1180#else
1181 return E_NOTIMPL;
1182#endif
1183}
1184
1185STDMETHODIMP Host::CreateUSBDeviceFilter(IN_BSTR aName,
1186 IHostUSBDeviceFilter **aFilter)
1187{
1188#ifdef VBOX_WITH_USB
1189 CheckComArgStrNotEmptyOrNull(aName);
1190 CheckComArgOutPointerValid(aFilter);
1191
1192 AutoCaller autoCaller(this);
1193 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1194
1195 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1196
1197 ComObjPtr<HostUSBDeviceFilter> filter;
1198 filter.createObject();
1199 HRESULT rc = filter->init(this, aName);
1200 ComAssertComRCRet(rc, rc);
1201 rc = filter.queryInterfaceTo(aFilter);
1202 AssertComRCReturn(rc, rc);
1203 return S_OK;
1204#else
1205 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1206 * extended error info to indicate that USB is simply not available
1207 * (w/o treating it as a failure), for example, as in OSE. */
1208 NOREF(aName);
1209 NOREF(aFilter);
1210 ReturnComNotImplemented();
1211#endif
1212}
1213
1214STDMETHODIMP Host::InsertUSBDeviceFilter(ULONG aPosition,
1215 IHostUSBDeviceFilter *aFilter)
1216{
1217#ifdef VBOX_WITH_USB
1218 CheckComArgNotNull(aFilter);
1219
1220 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1221 AutoCaller autoCaller(this);
1222 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1223
1224 AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1225
1226 clearError();
1227 MultiResult rc = checkUSBProxyService();
1228 if (FAILED(rc)) return rc;
1229
1230 ComObjPtr<HostUSBDeviceFilter> pFilter;
1231 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
1232 it != m->llChildren.end();
1233 ++it)
1234 {
1235 if (*it == aFilter)
1236 {
1237 pFilter = *it;
1238 break;
1239 }
1240 }
1241 if (pFilter.isNull())
1242 return setError(VBOX_E_INVALID_OBJECT_STATE,
1243 tr("The given USB device filter is not created within this VirtualBox instance"));
1244
1245 if (pFilter->mInList)
1246 return setError(E_INVALIDARG,
1247 tr("The given USB device filter is already in the list"));
1248
1249 /* iterate to the position... */
1250 USBDeviceFilterList::iterator itPos = m->llUSBDeviceFilters.begin();
1251 std::advance(itPos, aPosition);
1252 /* ...and insert */
1253 m->llUSBDeviceFilters.insert(itPos, pFilter);
1254 pFilter->mInList = true;
1255
1256 /* notify the proxy (only when the filter is active) */
1257 if ( m->pUSBProxyService->isActive()
1258 && pFilter->getData().mActive)
1259 {
1260 ComAssertRet(pFilter->getId() == NULL, E_FAIL);
1261 pFilter->getId() = m->pUSBProxyService->insertFilter(&pFilter->getData().mUSBFilter);
1262 }
1263
1264 // save the global settings; for that we should hold only the VirtualBox lock
1265 alock.release();
1266 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
1267 return rc = m->pParent->saveSettings();
1268#else
1269 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1270 * extended error info to indicate that USB is simply not available
1271 * (w/o treating it as a failure), for example, as in OSE. */
1272 NOREF(aPosition);
1273 NOREF(aFilter);
1274 ReturnComNotImplemented();
1275#endif
1276}
1277
1278STDMETHODIMP Host::RemoveUSBDeviceFilter(ULONG aPosition)
1279{
1280#ifdef VBOX_WITH_USB
1281
1282 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1283 AutoCaller autoCaller(this);
1284 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1285
1286 AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1287
1288 clearError();
1289 MultiResult rc = checkUSBProxyService();
1290 if (FAILED(rc)) return rc;
1291
1292 if (!m->llUSBDeviceFilters.size())
1293 return setError(E_INVALIDARG,
1294 tr("The USB device filter list is empty"));
1295
1296 if (aPosition >= m->llUSBDeviceFilters.size())
1297 return setError(E_INVALIDARG,
1298 tr("Invalid position: %lu (must be in range [0, %lu])"),
1299 aPosition, m->llUSBDeviceFilters.size() - 1);
1300
1301 ComObjPtr<HostUSBDeviceFilter> filter;
1302 {
1303 /* iterate to the position... */
1304 USBDeviceFilterList::iterator it = m->llUSBDeviceFilters.begin();
1305 std::advance (it, aPosition);
1306 /* ...get an element from there... */
1307 filter = *it;
1308 /* ...and remove */
1309 filter->mInList = false;
1310 m->llUSBDeviceFilters.erase(it);
1311 }
1312
1313 /* notify the proxy (only when the filter is active) */
1314 if (m->pUSBProxyService->isActive() && filter->getData().mActive)
1315 {
1316 ComAssertRet(filter->getId() != NULL, E_FAIL);
1317 m->pUSBProxyService->removeFilter(filter->getId());
1318 filter->getId() = NULL;
1319 }
1320
1321 // save the global settings; for that we should hold only the VirtualBox lock
1322 alock.release();
1323 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
1324 return rc = m->pParent->saveSettings();
1325#else
1326 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1327 * extended error info to indicate that USB is simply not available
1328 * (w/o treating it as a failure), for example, as in OSE. */
1329 NOREF(aPosition);
1330 ReturnComNotImplemented();
1331#endif
1332}
1333
1334STDMETHODIMP Host::FindHostDVDDrive(IN_BSTR aName, IMedium **aDrive)
1335{
1336 CheckComArgStrNotEmptyOrNull(aName);
1337 CheckComArgOutPointerValid(aDrive);
1338
1339 ComObjPtr<Medium>medium;
1340 HRESULT rc = findHostDriveByNameOrId(DeviceType_DVD, Utf8Str(aName), medium);
1341 if (SUCCEEDED(rc))
1342 return medium.queryInterfaceTo(aDrive);
1343 else
1344 return setError(rc, Medium::tr("The host DVD drive named '%ls' could not be found"), aName);
1345}
1346
1347STDMETHODIMP Host::FindHostFloppyDrive(IN_BSTR aName, IMedium **aDrive)
1348{
1349 CheckComArgStrNotEmptyOrNull(aName);
1350 CheckComArgOutPointerValid(aDrive);
1351
1352 *aDrive = NULL;
1353
1354 ComObjPtr<Medium>medium;
1355 HRESULT rc = findHostDriveByNameOrId(DeviceType_Floppy, Utf8Str(aName), medium);
1356 if (SUCCEEDED(rc))
1357 return medium.queryInterfaceTo(aDrive);
1358 else
1359 return setError(rc, Medium::tr("The host floppy drive named '%ls' could not be found"), aName);
1360}
1361
1362STDMETHODIMP Host::FindHostNetworkInterfaceByName(IN_BSTR name, IHostNetworkInterface **networkInterface)
1363{
1364#ifndef VBOX_WITH_HOSTNETIF_API
1365 return E_NOTIMPL;
1366#else
1367 if (!name)
1368 return E_INVALIDARG;
1369 if (!networkInterface)
1370 return E_POINTER;
1371
1372 *networkInterface = NULL;
1373 ComObjPtr<HostNetworkInterface> found;
1374 std::list <ComObjPtr<HostNetworkInterface> > list;
1375 int rc = NetIfList(list);
1376 if (RT_FAILURE(rc))
1377 {
1378 Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
1379 return E_FAIL;
1380 }
1381 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
1382 for (it = list.begin(); it != list.end(); ++it)
1383 {
1384 Bstr n;
1385 (*it)->COMGETTER(Name) (n.asOutParam());
1386 if (n == name)
1387 found = *it;
1388 }
1389
1390 if (!found)
1391 return setError(E_INVALIDARG,
1392 HostNetworkInterface::tr("The host network interface with the given name could not be found"));
1393
1394 found->setVirtualBox(m->pParent);
1395
1396 return found.queryInterfaceTo(networkInterface);
1397#endif
1398}
1399
1400STDMETHODIMP Host::FindHostNetworkInterfaceById(IN_BSTR id, IHostNetworkInterface **networkInterface)
1401{
1402#ifndef VBOX_WITH_HOSTNETIF_API
1403 return E_NOTIMPL;
1404#else
1405 if (Guid(id).isEmpty())
1406 return E_INVALIDARG;
1407 if (!networkInterface)
1408 return E_POINTER;
1409
1410 *networkInterface = NULL;
1411 ComObjPtr<HostNetworkInterface> found;
1412 std::list <ComObjPtr<HostNetworkInterface> > list;
1413 int rc = NetIfList(list);
1414 if (RT_FAILURE(rc))
1415 {
1416 Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
1417 return E_FAIL;
1418 }
1419 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
1420 for (it = list.begin(); it != list.end(); ++it)
1421 {
1422 Bstr g;
1423 (*it)->COMGETTER(Id) (g.asOutParam());
1424 if (g == id)
1425 found = *it;
1426 }
1427
1428 if (!found)
1429 return setError(E_INVALIDARG,
1430 HostNetworkInterface::tr("The host network interface with the given GUID could not be found"));
1431
1432 found->setVirtualBox(m->pParent);
1433
1434 return found.queryInterfaceTo(networkInterface);
1435#endif
1436}
1437
1438STDMETHODIMP Host::FindHostNetworkInterfacesOfType(HostNetworkInterfaceType_T type,
1439 ComSafeArrayOut(IHostNetworkInterface *, aNetworkInterfaces))
1440{
1441#ifdef VBOX_WITH_HOSTNETIF_API
1442 std::list <ComObjPtr<HostNetworkInterface> > allList;
1443 int rc = NetIfList(allList);
1444 if (RT_FAILURE(rc))
1445 return E_FAIL;
1446
1447 std::list <ComObjPtr<HostNetworkInterface> > resultList;
1448
1449 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
1450 for (it = allList.begin(); it != allList.end(); ++it)
1451 {
1452 HostNetworkInterfaceType_T t;
1453 HRESULT hr = (*it)->COMGETTER(InterfaceType)(&t);
1454 if (FAILED(hr))
1455 return hr;
1456
1457 if (t == type)
1458 {
1459 (*it)->setVirtualBox(m->pParent);
1460 resultList.push_back (*it);
1461 }
1462 }
1463
1464 SafeIfaceArray<IHostNetworkInterface> filteredNetworkInterfaces (resultList);
1465 filteredNetworkInterfaces.detachTo(ComSafeArrayOutArg(aNetworkInterfaces));
1466
1467 return S_OK;
1468#else
1469 return E_NOTIMPL;
1470#endif
1471}
1472
1473STDMETHODIMP Host::FindUSBDeviceByAddress(IN_BSTR aAddress,
1474 IHostUSBDevice **aDevice)
1475{
1476#ifdef VBOX_WITH_USB
1477 CheckComArgStrNotEmptyOrNull(aAddress);
1478 CheckComArgOutPointerValid(aDevice);
1479
1480 *aDevice = NULL;
1481
1482 SafeIfaceArray<IHostUSBDevice> devsvec;
1483 HRESULT rc = COMGETTER(USBDevices) (ComSafeArrayAsOutParam(devsvec));
1484 if (FAILED(rc)) return rc;
1485
1486 for (size_t i = 0; i < devsvec.size(); ++i)
1487 {
1488 Bstr address;
1489 rc = devsvec[i]->COMGETTER(Address) (address.asOutParam());
1490 if (FAILED(rc)) return rc;
1491 if (address == aAddress)
1492 {
1493 return ComObjPtr<IHostUSBDevice> (devsvec[i]).queryInterfaceTo(aDevice);
1494 }
1495 }
1496
1497 return setErrorNoLog(VBOX_E_OBJECT_NOT_FOUND,
1498 tr("Could not find a USB device with address '%ls'"),
1499 aAddress);
1500
1501#else /* !VBOX_WITH_USB */
1502 NOREF(aAddress);
1503 NOREF(aDevice);
1504 return E_NOTIMPL;
1505#endif /* !VBOX_WITH_USB */
1506}
1507
1508STDMETHODIMP Host::FindUSBDeviceById(IN_BSTR aId,
1509 IHostUSBDevice **aDevice)
1510{
1511#ifdef VBOX_WITH_USB
1512 CheckComArgExpr(aId, Guid (aId).isEmpty() == false);
1513 CheckComArgOutPointerValid(aDevice);
1514
1515 *aDevice = NULL;
1516
1517 SafeIfaceArray<IHostUSBDevice> devsvec;
1518 HRESULT rc = COMGETTER(USBDevices) (ComSafeArrayAsOutParam(devsvec));
1519 if (FAILED(rc)) return rc;
1520
1521 for (size_t i = 0; i < devsvec.size(); ++i)
1522 {
1523 Bstr id;
1524 rc = devsvec[i]->COMGETTER(Id) (id.asOutParam());
1525 if (FAILED(rc)) return rc;
1526 if (id == aId)
1527 {
1528 return ComObjPtr<IHostUSBDevice> (devsvec[i]).queryInterfaceTo(aDevice);
1529 }
1530 }
1531
1532 return setErrorNoLog (VBOX_E_OBJECT_NOT_FOUND, tr (
1533 "Could not find a USB device with uuid {%RTuuid}"),
1534 Guid (aId).raw());
1535
1536#else /* !VBOX_WITH_USB */
1537 NOREF(aId);
1538 NOREF(aDevice);
1539 return E_NOTIMPL;
1540#endif /* !VBOX_WITH_USB */
1541}
1542
1543STDMETHODIMP Host::GenerateMACAddress(BSTR *aAddress)
1544{
1545 CheckComArgOutPointerValid(aAddress);
1546 // no locking required
1547 Utf8Str mac;
1548 generateMACAddress(mac);
1549 Bstr(mac).cloneTo(aAddress);
1550 return S_OK;
1551}
1552
1553// public methods only for internal purposes
1554////////////////////////////////////////////////////////////////////////////////
1555
1556HRESULT Host::loadSettings(const settings::Host &data)
1557{
1558 HRESULT rc = S_OK;
1559#ifdef VBOX_WITH_USB
1560 AutoCaller autoCaller(this);
1561 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1562
1563 AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1564
1565 for (settings::USBDeviceFiltersList::const_iterator it = data.llUSBDeviceFilters.begin();
1566 it != data.llUSBDeviceFilters.end();
1567 ++it)
1568 {
1569 const settings::USBDeviceFilter &f = *it;
1570 ComObjPtr<HostUSBDeviceFilter> pFilter;
1571 pFilter.createObject();
1572 rc = pFilter->init(this, f);
1573 if (FAILED(rc)) break;
1574
1575 m->llUSBDeviceFilters.push_back(pFilter);
1576 pFilter->mInList = true;
1577
1578 /* notify the proxy (only when the filter is active) */
1579 if (pFilter->getData().mActive)
1580 {
1581 HostUSBDeviceFilter *flt = pFilter; /* resolve ambiguity */
1582 flt->getId() = m->pUSBProxyService->insertFilter(&pFilter->getData().mUSBFilter);
1583 }
1584 }
1585#else
1586 NOREF(data);
1587#endif /* VBOX_WITH_USB */
1588 return rc;
1589}
1590
1591HRESULT Host::saveSettings(settings::Host &data)
1592{
1593#ifdef VBOX_WITH_USB
1594 AutoCaller autoCaller(this);
1595 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1596
1597 AutoReadLock alock1(this COMMA_LOCKVAL_SRC_POS);
1598 AutoReadLock alock2(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1599
1600 data.llUSBDeviceFilters.clear();
1601
1602 for (USBDeviceFilterList::const_iterator it = m->llUSBDeviceFilters.begin();
1603 it != m->llUSBDeviceFilters.end();
1604 ++it)
1605 {
1606 ComObjPtr<HostUSBDeviceFilter> pFilter = *it;
1607 settings::USBDeviceFilter f;
1608 pFilter->saveSettings(f);
1609 data.llUSBDeviceFilters.push_back(f);
1610 }
1611#else
1612 NOREF(data);
1613#endif /* VBOX_WITH_USB */
1614
1615 return S_OK;
1616}
1617
1618/**
1619 * Sets the given pointer to point to the static list of DVD or floppy
1620 * drives in the Host instance data, depending on the @a mediumType
1621 * parameter.
1622 *
1623 * This builds the list on the first call; it adds or removes host drives
1624 * that may have changed if fRefresh == true.
1625 *
1626 * The caller must hold the medium tree write lock before calling this.
1627 * To protect the list to which the caller's pointer points, the caller
1628 * must also hold that lock.
1629 *
1630 * @param mediumType Must be DeviceType_Floppy or DeviceType_DVD.
1631 * @param fRefresh Whether to refresh the host drives list even if this is not the first call.
1632 * @param pll Caller's pointer which gets set to the static list of host drives.
1633 * @return
1634 */
1635HRESULT Host::getDrives(DeviceType_T mediumType,
1636 bool fRefresh,
1637 MediaList *&pll)
1638{
1639 HRESULT rc = S_OK;
1640 Assert(m->pParent->getMediaTreeLockHandle().isWriteLockOnCurrentThread());
1641
1642 MediaList llNew;
1643 MediaList *pllCached;
1644 bool *pfListBuilt = NULL;
1645
1646 switch (mediumType)
1647 {
1648 case DeviceType_DVD:
1649 if (!m->fDVDDrivesListBuilt || fRefresh)
1650 {
1651 rc = buildDVDDrivesList(llNew);
1652 if (FAILED(rc))
1653 return rc;
1654 pfListBuilt = &m->fDVDDrivesListBuilt;
1655 }
1656 pllCached = &m->llDVDDrives;
1657 break;
1658
1659 case DeviceType_Floppy:
1660 if (!m->fFloppyDrivesListBuilt || fRefresh)
1661 {
1662 rc = buildFloppyDrivesList(llNew);
1663 if (FAILED(rc))
1664 return rc;
1665 pfListBuilt = &m->fFloppyDrivesListBuilt;
1666 }
1667 pllCached = &m->llFloppyDrives;
1668 break;
1669
1670 default:
1671 return E_INVALIDARG;
1672 }
1673
1674 if (pfListBuilt)
1675 {
1676 // a list was built in llNew above:
1677 if (!*pfListBuilt)
1678 {
1679 // this was the first call (instance bool is still false): then just copy the whole list and return
1680 *pllCached = llNew;
1681 // and mark the instance data as "built"
1682 *pfListBuilt = true;
1683 }
1684 else
1685 {
1686 // list was built, and this was a subsequent call: then compare the old and the new lists
1687
1688 // remove drives from the cached list which are no longer present
1689 for (MediaList::iterator itCached = pllCached->begin();
1690 itCached != pllCached->end();
1691 /*nothing */)
1692 {
1693 Medium *pCached = *itCached;
1694 const Utf8Str strLocationCached = pCached->getLocationFull();
1695 bool fFound = false;
1696 for (MediaList::iterator itNew = llNew.begin();
1697 itNew != llNew.end();
1698 ++itNew)
1699 {
1700 Medium *pNew = *itNew;
1701 const Utf8Str strLocationNew = pNew->getLocationFull();
1702 if (strLocationNew == strLocationCached)
1703 {
1704 fFound = true;
1705 break;
1706 }
1707 }
1708 if (!fFound)
1709 itCached = pllCached->erase(itCached);
1710 else
1711 ++itCached;
1712 }
1713
1714 // add drives to the cached list that are not on there yet
1715 for (MediaList::iterator itNew = llNew.begin();
1716 itNew != llNew.end();
1717 ++itNew)
1718 {
1719 Medium *pNew = *itNew;
1720 const Utf8Str strLocationNew = pNew->getLocationFull();
1721 bool fFound = false;
1722 for (MediaList::iterator itCached = pllCached->begin();
1723 itCached != pllCached->end();
1724 ++itCached)
1725 {
1726 Medium *pCached = *itCached;
1727 const Utf8Str strLocationCached = pCached->getLocationFull();
1728 if (strLocationNew == strLocationCached)
1729 {
1730 fFound = true;
1731 break;
1732 }
1733 }
1734
1735 if (!fFound)
1736 pllCached->push_back(pNew);
1737 }
1738 }
1739 }
1740
1741 // return cached list to caller
1742 pll = pllCached;
1743
1744 return rc;
1745}
1746
1747/**
1748 * Goes through the list of host drives that would be returned by getDrives()
1749 * and looks for a host drive with the given UUID. If found, it sets pMedium
1750 * to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
1751 *
1752 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
1753 * @param uuid Medium UUID of host drive to look for.
1754 * @param fRefresh Whether to refresh the host drives list (see getDrives())
1755 * @param pMedium Medium object, if found…
1756 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
1757 */
1758HRESULT Host::findHostDriveById(DeviceType_T mediumType,
1759 const Guid &uuid,
1760 bool fRefresh,
1761 ComObjPtr<Medium> &pMedium)
1762{
1763 MediaList *pllMedia;
1764
1765 AutoWriteLock wlock(m->pParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
1766 HRESULT rc = getDrives(mediumType, fRefresh, pllMedia);
1767 if (SUCCEEDED(rc))
1768 {
1769 for (MediaList::iterator it = pllMedia->begin();
1770 it != pllMedia->end();
1771 ++it)
1772 {
1773 Medium *pThis = *it;
1774 AutoCaller mediumCaller(pThis);
1775 AutoReadLock mediumLock(pThis COMMA_LOCKVAL_SRC_POS);
1776 if (pThis->getId() == uuid)
1777 {
1778 pMedium = pThis;
1779 return S_OK;
1780 }
1781 }
1782 }
1783
1784 return VBOX_E_OBJECT_NOT_FOUND;
1785}
1786
1787/**
1788 * Goes through the list of host drives that would be returned by getDrives()
1789 * and looks for a host drive with the given name. If found, it sets pMedium
1790 * to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
1791 *
1792 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
1793 * @param strLocationFull Name (path) of host drive to look for.
1794 * @param fRefresh Whether to refresh the host drives list (see getDrives())
1795 * @param pMedium Medium object, if found…
1796 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
1797 */
1798HRESULT Host::findHostDriveByName(DeviceType_T mediumType,
1799 const Utf8Str &strLocationFull,
1800 bool fRefresh,
1801 ComObjPtr<Medium> &pMedium)
1802{
1803 MediaList *pllMedia;
1804
1805 AutoWriteLock wlock(m->pParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
1806 HRESULT rc = getDrives(mediumType, fRefresh, pllMedia);
1807 if (SUCCEEDED(rc))
1808 {
1809 for (MediaList::iterator it = pllMedia->begin();
1810 it != pllMedia->end();
1811 ++it)
1812 {
1813 Medium *pThis = *it;
1814 AutoCaller mediumCaller(pThis);
1815 AutoReadLock mediumLock(pThis COMMA_LOCKVAL_SRC_POS);
1816 if (pThis->getLocationFull() == strLocationFull)
1817 {
1818 pMedium = pThis;
1819 return S_OK;
1820 }
1821 }
1822 }
1823
1824 return VBOX_E_OBJECT_NOT_FOUND;
1825}
1826
1827/**
1828 * Goes through the list of host drives that would be returned by getDrives()
1829 * and looks for a host drive with the given name, location or ID. If found,
1830 * it sets pMedium to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
1831 *
1832 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
1833 * @param strNameOrId Name or full location or UUID of host drive to look for.
1834 * @param pMedium Medium object, if found…
1835 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
1836 */
1837HRESULT Host::findHostDriveByNameOrId(DeviceType_T mediumType,
1838 const Utf8Str &strNameOrId,
1839 ComObjPtr<Medium> &pMedium)
1840{
1841 AutoWriteLock wlock(m->pParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
1842
1843 Guid uuid(strNameOrId);
1844 if (!uuid.isEmpty())
1845 return findHostDriveById(mediumType, uuid, true /* fRefresh */, pMedium);
1846
1847 // string is not a syntactically valid UUID: try a name then
1848 return findHostDriveByName(mediumType, strNameOrId, true /* fRefresh */, pMedium);
1849}
1850
1851/**
1852 * Called from getDrives() to build the DVD drives list.
1853 * @param pll
1854 * @return
1855 */
1856HRESULT Host::buildDVDDrivesList(MediaList &list)
1857{
1858 HRESULT rc = S_OK;
1859
1860 Assert(m->pParent->getMediaTreeLockHandle().isWriteLockOnCurrentThread());
1861
1862 try
1863 {
1864#if defined(RT_OS_WINDOWS)
1865 int sz = GetLogicalDriveStrings(0, NULL);
1866 TCHAR *hostDrives = new TCHAR[sz+1];
1867 GetLogicalDriveStrings(sz, hostDrives);
1868 wchar_t driveName[3] = { '?', ':', '\0' };
1869 TCHAR *p = hostDrives;
1870 do
1871 {
1872 if (GetDriveType(p) == DRIVE_CDROM)
1873 {
1874 driveName[0] = *p;
1875 ComObjPtr<Medium> hostDVDDriveObj;
1876 hostDVDDriveObj.createObject();
1877 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(driveName));
1878 list.push_back(hostDVDDriveObj);
1879 }
1880 p += _tcslen(p) + 1;
1881 }
1882 while (*p);
1883 delete[] hostDrives;
1884
1885#elif defined(RT_OS_SOLARIS)
1886# ifdef VBOX_USE_LIBHAL
1887 if (!getDVDInfoFromHal(list))
1888# endif
1889 {
1890 getDVDInfoFromDevTree(list);
1891 }
1892
1893#elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
1894 if (RT_SUCCESS(m->hostDrives.updateDVDs()))
1895 for (DriveInfoList::const_iterator it = m->hostDrives.DVDBegin();
1896 SUCCEEDED(rc) && it != m->hostDrives.DVDEnd(); ++it)
1897 {
1898 ComObjPtr<Medium> hostDVDDriveObj;
1899 Utf8Str location(it->mDevice);
1900 Utf8Str description(it->mDescription);
1901 if (SUCCEEDED(rc))
1902 rc = hostDVDDriveObj.createObject();
1903 if (SUCCEEDED(rc))
1904 rc = hostDVDDriveObj->init(m->pParent, DeviceType_DVD, location, description);
1905 if (SUCCEEDED(rc))
1906 list.push_back(hostDVDDriveObj);
1907 }
1908#elif defined(RT_OS_DARWIN)
1909 PDARWINDVD cur = DarwinGetDVDDrives();
1910 while (cur)
1911 {
1912 ComObjPtr<Medium> hostDVDDriveObj;
1913 hostDVDDriveObj.createObject();
1914 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(cur->szName));
1915 list.push_back(hostDVDDriveObj);
1916
1917 /* next */
1918 void *freeMe = cur;
1919 cur = cur->pNext;
1920 RTMemFree(freeMe);
1921 }
1922#else
1923 /* PORTME */
1924#endif
1925 }
1926 catch(std::bad_alloc &)
1927 {
1928 rc = E_OUTOFMEMORY;
1929 }
1930 return rc;
1931}
1932
1933/**
1934 * Called from getDrives() to build the floppy drives list.
1935 * @param list
1936 * @return
1937 */
1938HRESULT Host::buildFloppyDrivesList(MediaList &list)
1939{
1940 HRESULT rc = S_OK;
1941
1942 Assert(m->pParent->getMediaTreeLockHandle().isWriteLockOnCurrentThread());
1943
1944 try
1945 {
1946#ifdef RT_OS_WINDOWS
1947 int sz = GetLogicalDriveStrings(0, NULL);
1948 TCHAR *hostDrives = new TCHAR[sz+1];
1949 GetLogicalDriveStrings(sz, hostDrives);
1950 wchar_t driveName[3] = { '?', ':', '\0' };
1951 TCHAR *p = hostDrives;
1952 do
1953 {
1954 if (GetDriveType(p) == DRIVE_REMOVABLE)
1955 {
1956 driveName[0] = *p;
1957 ComObjPtr<Medium> hostFloppyDriveObj;
1958 hostFloppyDriveObj.createObject();
1959 hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, Bstr(driveName));
1960 list.push_back(hostFloppyDriveObj);
1961 }
1962 p += _tcslen(p) + 1;
1963 }
1964 while (*p);
1965 delete[] hostDrives;
1966#elif defined(RT_OS_LINUX)
1967 if (RT_SUCCESS(m->hostDrives.updateFloppies()))
1968 for (DriveInfoList::const_iterator it = m->hostDrives.FloppyBegin();
1969 SUCCEEDED(rc) && it != m->hostDrives.FloppyEnd(); ++it)
1970 {
1971 ComObjPtr<Medium> hostFloppyDriveObj;
1972 Utf8Str location(it->mDevice);
1973 Utf8Str description(it->mDescription);
1974 if (SUCCEEDED(rc))
1975 rc = hostFloppyDriveObj.createObject();
1976 if (SUCCEEDED(rc))
1977 rc = hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, location, description);
1978 if (SUCCEEDED(rc))
1979 list.push_back(hostFloppyDriveObj);
1980 }
1981#else
1982 NOREF(list);
1983 /* PORTME */
1984#endif
1985 }
1986 catch(std::bad_alloc &)
1987 {
1988 rc = E_OUTOFMEMORY;
1989 }
1990
1991 return rc;
1992}
1993
1994#ifdef VBOX_WITH_USB
1995USBProxyService* Host::usbProxyService()
1996{
1997 return m->pUSBProxyService;
1998}
1999
2000HRESULT Host::addChild(HostUSBDeviceFilter *pChild)
2001{
2002 AutoCaller autoCaller(this);
2003 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2004
2005 AutoWriteLock alock(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
2006
2007 m->llChildren.push_back(pChild);
2008
2009 return S_OK;
2010}
2011
2012HRESULT Host::removeChild(HostUSBDeviceFilter *pChild)
2013{
2014 AutoCaller autoCaller(this);
2015 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2016
2017 AutoWriteLock alock(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
2018
2019 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
2020 it != m->llChildren.end();
2021 ++it)
2022 {
2023 if (*it == pChild)
2024 {
2025 m->llChildren.erase(it);
2026 break;
2027 }
2028 }
2029
2030 return S_OK;
2031}
2032
2033VirtualBox* Host::parent()
2034{
2035 return m->pParent;
2036}
2037
2038/**
2039 * Called by setter methods of all USB device filters.
2040 */
2041HRESULT Host::onUSBDeviceFilterChange(HostUSBDeviceFilter *aFilter,
2042 BOOL aActiveChanged /* = FALSE */)
2043{
2044 AutoCaller autoCaller(this);
2045 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2046
2047 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2048
2049 if (aFilter->mInList)
2050 {
2051 if (aActiveChanged)
2052 {
2053 // insert/remove the filter from the proxy
2054 if (aFilter->getData().mActive)
2055 {
2056 ComAssertRet(aFilter->getId() == NULL, E_FAIL);
2057 aFilter->getId() = m->pUSBProxyService->insertFilter(&aFilter->getData().mUSBFilter);
2058 }
2059 else
2060 {
2061 ComAssertRet(aFilter->getId() != NULL, E_FAIL);
2062 m->pUSBProxyService->removeFilter(aFilter->getId());
2063 aFilter->getId() = NULL;
2064 }
2065 }
2066 else
2067 {
2068 if (aFilter->getData().mActive)
2069 {
2070 // update the filter in the proxy
2071 ComAssertRet(aFilter->getId() != NULL, E_FAIL);
2072 m->pUSBProxyService->removeFilter(aFilter->getId());
2073 aFilter->getId() = m->pUSBProxyService->insertFilter(&aFilter->getData().mUSBFilter);
2074 }
2075 }
2076
2077 // save the global settings... yeah, on every single filter property change
2078 // for that we should hold only the VirtualBox lock
2079 alock.release();
2080 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
2081 return m->pParent->saveSettings();
2082 }
2083
2084 return S_OK;
2085}
2086
2087
2088/**
2089 * Interface for obtaining a copy of the USBDeviceFilterList,
2090 * used by the USBProxyService.
2091 *
2092 * @param aGlobalFilters Where to put the global filter list copy.
2093 * @param aMachines Where to put the machine vector.
2094 */
2095void Host::getUSBFilters(Host::USBDeviceFilterList *aGlobalFilters)
2096{
2097 AutoReadLock alock(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
2098
2099 *aGlobalFilters = m->llUSBDeviceFilters;
2100}
2101
2102#endif /* VBOX_WITH_USB */
2103
2104// private methods
2105////////////////////////////////////////////////////////////////////////////////
2106
2107#if defined(RT_OS_SOLARIS) && defined(VBOX_USE_LIBHAL)
2108
2109/**
2110 * Helper function to get the slice number from a device path
2111 *
2112 * @param pszDevLinkPath Pointer to a device path (/dev/(r)dsk/c7d1t0d0s3 etc.)
2113 * @returns Pointer to the slice portion of the given path.
2114 */
2115static char *solarisGetSliceFromPath(const char *pszDevLinkPath)
2116{
2117 char *pszFound = NULL;
2118 char *pszSlice = strrchr(pszDevLinkPath, 's');
2119 char *pszDisk = strrchr(pszDevLinkPath, 'd');
2120 if (pszSlice && pszSlice > pszDisk)
2121 pszFound = pszSlice;
2122 else
2123 pszFound = pszDisk;
2124
2125 if (pszFound && RT_C_IS_DIGIT(pszFound[1]))
2126 return pszFound;
2127
2128 return NULL;
2129}
2130
2131/**
2132 * Walk device links and returns an allocated path for the first one in the snapshot.
2133 *
2134 * @param DevLink Handle to the device link being walked.
2135 * @param pvArg Opaque data containing the pointer to the path.
2136 * @returns Pointer to an allocated device path string.
2137 */
2138static int solarisWalkDevLink(di_devlink_t DevLink, void *pvArg)
2139{
2140 char **ppszPath = (char **)pvArg;
2141 *ppszPath = strdup(di_devlink_path(DevLink));
2142 return DI_WALK_TERMINATE;
2143}
2144
2145/**
2146 * Walk all devices in the system and enumerate CD/DVD drives.
2147 * @param Node Handle to the current node.
2148 * @param pvArg Opaque data (holds list pointer).
2149 * @returns Solaris specific code whether to continue walking or not.
2150 */
2151static int solarisWalkDeviceNodeForDVD(di_node_t Node, void *pvArg)
2152{
2153 PSOLARISDVD *ppDrives = (PSOLARISDVD *)pvArg;
2154
2155 /*
2156 * Check for "removable-media" or "hotpluggable" instead of "SCSI" so that we also include USB CD-ROMs.
2157 * As unfortunately the Solaris drivers only export these common properties.
2158 */
2159 int *pInt = NULL;
2160 if ( di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "removable-media", &pInt) >= 0
2161 || di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "hotpluggable", &pInt) >= 0)
2162 {
2163 if (di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "inquiry-device-type", &pInt) > 0
2164 && ( *pInt == DTYPE_RODIRECT /* CDROM */
2165 || *pInt == DTYPE_OPTICAL)) /* Optical Drive */
2166 {
2167 char *pszProduct = NULL;
2168 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-product-id", &pszProduct) > 0)
2169 {
2170 char *pszVendor = NULL;
2171 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-vendor-id", &pszVendor) > 0)
2172 {
2173 /*
2174 * Found a DVD drive, we need to scan the minor nodes to find the correct
2175 * slice that represents the whole drive. "s2" is always the whole drive for CD/DVDs.
2176 */
2177 int Major = di_driver_major(Node);
2178 di_minor_t Minor = DI_MINOR_NIL;
2179 di_devlink_handle_t DevLink = di_devlink_init(NULL /* name */, 0 /* flags */);
2180 if (DevLink)
2181 {
2182 while ((Minor = di_minor_next(Node, Minor)) != DI_MINOR_NIL)
2183 {
2184 dev_t Dev = di_minor_devt(Minor);
2185 if ( Major != (int)major(Dev)
2186 || di_minor_spectype(Minor) == S_IFBLK
2187 || di_minor_type(Minor) != DDM_MINOR)
2188 {
2189 continue;
2190 }
2191
2192 char *pszMinorPath = di_devfs_minor_path(Minor);
2193 if (!pszMinorPath)
2194 continue;
2195
2196 char *pszDevLinkPath = NULL;
2197 di_devlink_walk(DevLink, NULL, pszMinorPath, DI_PRIMARY_LINK, &pszDevLinkPath, solarisWalkDevLink);
2198 di_devfs_path_free(pszMinorPath);
2199
2200 if (pszDevLinkPath)
2201 {
2202 char *pszSlice = solarisGetSliceFromPath(pszDevLinkPath);
2203 if ( pszSlice && !strcmp(pszSlice, "s2")
2204 && !strncmp(pszDevLinkPath, "/dev/rdsk", sizeof("/dev/rdsk") - 1)) /* We want only raw disks */
2205 {
2206 /*
2207 * We've got a fully qualified DVD drive. Add it to the list.
2208 */
2209 PSOLARISDVD pDrive = (PSOLARISDVD)RTMemAllocZ(sizeof(SOLARISDVD));
2210 if (RT_LIKELY(pDrive))
2211 {
2212 RTStrPrintf(pDrive->szDescription, sizeof(pDrive->szDescription), "%s %s", pszVendor, pszProduct);
2213 RTStrCopy(pDrive->szRawDiskPath, sizeof(pDrive->szRawDiskPath), pszDevLinkPath);
2214 if (*ppDrives)
2215 pDrive->pNext = *ppDrives;
2216 *ppDrives = pDrive;
2217
2218 /* We're not interested in any of the other slices, stop minor nodes traversal. */
2219 free(pszDevLinkPath);
2220 break;
2221 }
2222 }
2223 free(pszDevLinkPath);
2224 }
2225 }
2226 di_devlink_fini(&DevLink);
2227 }
2228 }
2229 }
2230 }
2231 }
2232 return DI_WALK_CONTINUE;
2233}
2234
2235/**
2236 * Solaris specific function to enumerate CD/DVD drives via the device tree.
2237 * Works on Solaris 10 as well as OpenSolaris without depending on libhal.
2238 */
2239void Host::getDVDInfoFromDevTree(std::list<ComObjPtr<Medium> > &list)
2240{
2241 PSOLARISDVD pDrives = NULL;
2242 di_node_t RootNode = di_init("/", DINFOCPYALL);
2243 if (RootNode != DI_NODE_NIL)
2244 di_walk_node(RootNode, DI_WALK_CLDFIRST, &pDrives, solarisWalkDeviceNodeForDVD);
2245
2246 di_fini(RootNode);
2247
2248 while (pDrives)
2249 {
2250 ComObjPtr<Medium> hostDVDDriveObj;
2251 hostDVDDriveObj.createObject();
2252 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(pDrives->szRawDiskPath), Bstr(pDrives->szDescription));
2253 list.push_back(hostDVDDriveObj);
2254
2255 void *pvDrive = pDrives;
2256 pDrives = pDrives->pNext;
2257 RTMemFree(pvDrive);
2258 }
2259}
2260
2261/* Solaris hosts, loading libhal at runtime */
2262
2263/**
2264 * Helper function to query the hal subsystem for information about DVD drives attached to the
2265 * system.
2266 *
2267 * @returns true if information was successfully obtained, false otherwise
2268 * @retval list drives found will be attached to this list
2269 */
2270bool Host::getDVDInfoFromHal(std::list<ComObjPtr<Medium> > &list)
2271{
2272 bool halSuccess = false;
2273 DBusError dbusError;
2274 if (!gLibHalCheckPresence())
2275 return false;
2276 gDBusErrorInit (&dbusError);
2277 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
2278 if (dbusConnection != 0)
2279 {
2280 LibHalContext *halContext = gLibHalCtxNew();
2281 if (halContext != 0)
2282 {
2283 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
2284 {
2285 if (gLibHalCtxInit(halContext, &dbusError))
2286 {
2287 int numDevices;
2288 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
2289 "storage.drive_type", "cdrom",
2290 &numDevices, &dbusError);
2291 if (halDevices != 0)
2292 {
2293 /* Hal is installed and working, so if no devices are reported, assume
2294 that there are none. */
2295 halSuccess = true;
2296 for (int i = 0; i < numDevices; i++)
2297 {
2298 char *devNode = gLibHalDeviceGetPropertyString(halContext,
2299 halDevices[i], "block.device", &dbusError);
2300#ifdef RT_OS_SOLARIS
2301 /* The CD/DVD ioctls work only for raw device nodes. */
2302 char *tmp = getfullrawname(devNode);
2303 gLibHalFreeString(devNode);
2304 devNode = tmp;
2305#endif
2306
2307 if (devNode != 0)
2308 {
2309// if (validateDevice(devNode, true))
2310// {
2311 Utf8Str description;
2312 char *vendor, *product;
2313 /* We do not check the error here, as this field may
2314 not even exist. */
2315 vendor = gLibHalDeviceGetPropertyString(halContext,
2316 halDevices[i], "info.vendor", 0);
2317 product = gLibHalDeviceGetPropertyString(halContext,
2318 halDevices[i], "info.product", &dbusError);
2319 if ((product != 0 && product[0] != 0))
2320 {
2321 if ((vendor != 0) && (vendor[0] != 0))
2322 {
2323 description = Utf8StrFmt ("%s %s",
2324 vendor, product);
2325 }
2326 else
2327 {
2328 description = product;
2329 }
2330 ComObjPtr<Medium> hostDVDDriveObj;
2331 hostDVDDriveObj.createObject();
2332 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
2333 Bstr(devNode), Bstr(description));
2334 list.push_back (hostDVDDriveObj);
2335 }
2336 else
2337 {
2338 if (product == 0)
2339 {
2340 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
2341 halDevices[i], dbusError.name, dbusError.message));
2342 gDBusErrorFree(&dbusError);
2343 }
2344 ComObjPtr<Medium> hostDVDDriveObj;
2345 hostDVDDriveObj.createObject();
2346 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
2347 Bstr(devNode));
2348 list.push_back (hostDVDDriveObj);
2349 }
2350 if (vendor != 0)
2351 {
2352 gLibHalFreeString(vendor);
2353 }
2354 if (product != 0)
2355 {
2356 gLibHalFreeString(product);
2357 }
2358// }
2359// else
2360// {
2361// LogRel(("Host::COMGETTER(DVDDrives): failed to validate the block device %s as a DVD drive\n"));
2362// }
2363#ifndef RT_OS_SOLARIS
2364 gLibHalFreeString(devNode);
2365#else
2366 free(devNode);
2367#endif
2368 }
2369 else
2370 {
2371 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
2372 halDevices[i], dbusError.name, dbusError.message));
2373 gDBusErrorFree(&dbusError);
2374 }
2375 }
2376 gLibHalFreeStringArray(halDevices);
2377 }
2378 else
2379 {
2380 LogRel(("Host::COMGETTER(DVDDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2381 gDBusErrorFree(&dbusError);
2382 }
2383 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
2384 {
2385 LogRel(("Host::COMGETTER(DVDDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2386 gDBusErrorFree(&dbusError);
2387 }
2388 }
2389 else
2390 {
2391 LogRel(("Host::COMGETTER(DVDDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2392 gDBusErrorFree(&dbusError);
2393 }
2394 gLibHalCtxFree(halContext);
2395 }
2396 else
2397 {
2398 LogRel(("Host::COMGETTER(DVDDrives): failed to set libhal connection to dbus.\n"));
2399 }
2400 }
2401 else
2402 {
2403 LogRel(("Host::COMGETTER(DVDDrives): failed to get a libhal context - out of memory?\n"));
2404 }
2405 gDBusConnectionUnref(dbusConnection);
2406 }
2407 else
2408 {
2409 LogRel(("Host::COMGETTER(DVDDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2410 gDBusErrorFree(&dbusError);
2411 }
2412 return halSuccess;
2413}
2414
2415
2416/**
2417 * Helper function to query the hal subsystem for information about floppy drives attached to the
2418 * system.
2419 *
2420 * @returns true if information was successfully obtained, false otherwise
2421 * @retval list drives found will be attached to this list
2422 */
2423bool Host::getFloppyInfoFromHal(std::list< ComObjPtr<Medium> > &list)
2424{
2425 bool halSuccess = false;
2426 DBusError dbusError;
2427 if (!gLibHalCheckPresence())
2428 return false;
2429 gDBusErrorInit (&dbusError);
2430 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
2431 if (dbusConnection != 0)
2432 {
2433 LibHalContext *halContext = gLibHalCtxNew();
2434 if (halContext != 0)
2435 {
2436 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
2437 {
2438 if (gLibHalCtxInit(halContext, &dbusError))
2439 {
2440 int numDevices;
2441 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
2442 "storage.drive_type", "floppy",
2443 &numDevices, &dbusError);
2444 if (halDevices != 0)
2445 {
2446 /* Hal is installed and working, so if no devices are reported, assume
2447 that there are none. */
2448 halSuccess = true;
2449 for (int i = 0; i < numDevices; i++)
2450 {
2451 char *driveType = gLibHalDeviceGetPropertyString(halContext,
2452 halDevices[i], "storage.drive_type", 0);
2453 if (driveType != 0)
2454 {
2455 if (strcmp(driveType, "floppy") != 0)
2456 {
2457 gLibHalFreeString(driveType);
2458 continue;
2459 }
2460 gLibHalFreeString(driveType);
2461 }
2462 else
2463 {
2464 /* An error occurred. The attribute "storage.drive_type"
2465 probably didn't exist. */
2466 continue;
2467 }
2468 char *devNode = gLibHalDeviceGetPropertyString(halContext,
2469 halDevices[i], "block.device", &dbusError);
2470 if (devNode != 0)
2471 {
2472// if (validateDevice(devNode, false))
2473// {
2474 Utf8Str description;
2475 char *vendor, *product;
2476 /* We do not check the error here, as this field may
2477 not even exist. */
2478 vendor = gLibHalDeviceGetPropertyString(halContext,
2479 halDevices[i], "info.vendor", 0);
2480 product = gLibHalDeviceGetPropertyString(halContext,
2481 halDevices[i], "info.product", &dbusError);
2482 if ((product != 0) && (product[0] != 0))
2483 {
2484 if ((vendor != 0) && (vendor[0] != 0))
2485 {
2486 description = Utf8StrFmt ("%s %s",
2487 vendor, product);
2488 }
2489 else
2490 {
2491 description = product;
2492 }
2493 ComObjPtr<Medium> hostFloppyDrive;
2494 hostFloppyDrive.createObject();
2495 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
2496 Bstr(devNode), Bstr(description));
2497 list.push_back (hostFloppyDrive);
2498 }
2499 else
2500 {
2501 if (product == 0)
2502 {
2503 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
2504 halDevices[i], dbusError.name, dbusError.message));
2505 gDBusErrorFree(&dbusError);
2506 }
2507 ComObjPtr<Medium> hostFloppyDrive;
2508 hostFloppyDrive.createObject();
2509 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
2510 Bstr(devNode));
2511 list.push_back (hostFloppyDrive);
2512 }
2513 if (vendor != 0)
2514 {
2515 gLibHalFreeString(vendor);
2516 }
2517 if (product != 0)
2518 {
2519 gLibHalFreeString(product);
2520 }
2521// }
2522// else
2523// {
2524// LogRel(("Host::COMGETTER(FloppyDrives): failed to validate the block device %s as a floppy drive\n"));
2525// }
2526 gLibHalFreeString(devNode);
2527 }
2528 else
2529 {
2530 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
2531 halDevices[i], dbusError.name, dbusError.message));
2532 gDBusErrorFree(&dbusError);
2533 }
2534 }
2535 gLibHalFreeStringArray(halDevices);
2536 }
2537 else
2538 {
2539 LogRel(("Host::COMGETTER(FloppyDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2540 gDBusErrorFree(&dbusError);
2541 }
2542 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
2543 {
2544 LogRel(("Host::COMGETTER(FloppyDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2545 gDBusErrorFree(&dbusError);
2546 }
2547 }
2548 else
2549 {
2550 LogRel(("Host::COMGETTER(FloppyDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2551 gDBusErrorFree(&dbusError);
2552 }
2553 gLibHalCtxFree(halContext);
2554 }
2555 else
2556 {
2557 LogRel(("Host::COMGETTER(FloppyDrives): failed to set libhal connection to dbus.\n"));
2558 }
2559 }
2560 else
2561 {
2562 LogRel(("Host::COMGETTER(FloppyDrives): failed to get a libhal context - out of memory?\n"));
2563 }
2564 gDBusConnectionUnref(dbusConnection);
2565 }
2566 else
2567 {
2568 LogRel(("Host::COMGETTER(FloppyDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2569 gDBusErrorFree(&dbusError);
2570 }
2571 return halSuccess;
2572}
2573#endif /* RT_OS_SOLARIS and VBOX_USE_HAL */
2574
2575/** @todo get rid of dead code below - RT_OS_SOLARIS and RT_OS_LINUX are never both set */
2576#if defined(RT_OS_SOLARIS)
2577
2578/**
2579 * Helper function to parse the given mount file and add found entries
2580 */
2581void Host::parseMountTable(char *mountTable, std::list< ComObjPtr<Medium> > &list)
2582{
2583#ifdef RT_OS_LINUX
2584 FILE *mtab = setmntent(mountTable, "r");
2585 if (mtab)
2586 {
2587 struct mntent *mntent;
2588 char *mnt_type;
2589 char *mnt_dev;
2590 char *tmp;
2591 while ((mntent = getmntent(mtab)))
2592 {
2593 mnt_type = (char*)malloc(strlen(mntent->mnt_type) + 1);
2594 mnt_dev = (char*)malloc(strlen(mntent->mnt_fsname) + 1);
2595 strcpy(mnt_type, mntent->mnt_type);
2596 strcpy(mnt_dev, mntent->mnt_fsname);
2597 // supermount fs case
2598 if (strcmp(mnt_type, "supermount") == 0)
2599 {
2600 tmp = strstr(mntent->mnt_opts, "fs=");
2601 if (tmp)
2602 {
2603 free(mnt_type);
2604 mnt_type = strdup(tmp + strlen("fs="));
2605 if (mnt_type)
2606 {
2607 tmp = strchr(mnt_type, ',');
2608 if (tmp)
2609 *tmp = '\0';
2610 }
2611 }
2612 tmp = strstr(mntent->mnt_opts, "dev=");
2613 if (tmp)
2614 {
2615 free(mnt_dev);
2616 mnt_dev = strdup(tmp + strlen("dev="));
2617 if (mnt_dev)
2618 {
2619 tmp = strchr(mnt_dev, ',');
2620 if (tmp)
2621 *tmp = '\0';
2622 }
2623 }
2624 }
2625 // use strstr here to cover things fs types like "udf,iso9660"
2626 if (strstr(mnt_type, "iso9660") == 0)
2627 {
2628 /** @todo check whether we've already got the drive in our list! */
2629 if (validateDevice(mnt_dev, true))
2630 {
2631 ComObjPtr<Medium> hostDVDDriveObj;
2632 hostDVDDriveObj.createObject();
2633 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(mnt_dev));
2634 list.push_back (hostDVDDriveObj);
2635 }
2636 }
2637 free(mnt_dev);
2638 free(mnt_type);
2639 }
2640 endmntent(mtab);
2641 }
2642#else // RT_OS_SOLARIS
2643 FILE *mntFile = fopen(mountTable, "r");
2644 if (mntFile)
2645 {
2646 struct mnttab mntTab;
2647 while (getmntent(mntFile, &mntTab) == 0)
2648 {
2649 const char *mountName = mntTab.mnt_special;
2650 const char *mountPoint = mntTab.mnt_mountp;
2651 const char *mountFSType = mntTab.mnt_fstype;
2652 if (mountName && mountPoint && mountFSType)
2653 {
2654 // skip devices we are not interested in
2655 if ((*mountName && mountName[0] == '/') && // skip 'fake' devices (like -hosts, proc, fd, swap)
2656 (*mountFSType && (strncmp(mountFSType, "devfs", 5) != 0 && // skip devfs (i.e. /devices)
2657 strncmp(mountFSType, "dev", 3) != 0 && // skip dev (i.e. /dev)
2658 strncmp(mountFSType, "lofs", 4) != 0))) // skip loop-back file-system (lofs)
2659 {
2660 char *rawDevName = getfullrawname((char *)mountName);
2661 if (validateDevice(rawDevName, true))
2662 {
2663 ComObjPtr<Medium> hostDVDDriveObj;
2664 hostDVDDriveObj.createObject();
2665 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(rawDevName));
2666 list.push_back (hostDVDDriveObj);
2667 }
2668 free(rawDevName);
2669 }
2670 }
2671 }
2672
2673 fclose(mntFile);
2674 }
2675#endif
2676}
2677
2678/**
2679 * Helper function to check whether the given device node is a valid drive
2680 */
2681bool Host::validateDevice(const char *deviceNode, bool isCDROM)
2682{
2683 struct stat statInfo;
2684 bool retValue = false;
2685
2686 // sanity check
2687 if (!deviceNode)
2688 {
2689 return false;
2690 }
2691
2692 // first a simple stat() call
2693 if (stat(deviceNode, &statInfo) < 0)
2694 {
2695 return false;
2696 }
2697 else
2698 {
2699 if (isCDROM)
2700 {
2701 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2702 {
2703 int fileHandle;
2704 // now try to open the device
2705 fileHandle = open(deviceNode, O_RDONLY | O_NONBLOCK, 0);
2706 if (fileHandle >= 0)
2707 {
2708 cdrom_subchnl cdChannelInfo;
2709 cdChannelInfo.cdsc_format = CDROM_MSF;
2710 // this call will finally reveal the whole truth
2711#ifdef RT_OS_LINUX
2712 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2713 (errno == EIO) || (errno == ENOENT) ||
2714 (errno == EINVAL) || (errno == ENOMEDIUM))
2715#else
2716 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2717 (errno == EIO) || (errno == ENOENT) ||
2718 (errno == EINVAL))
2719#endif
2720 {
2721 retValue = true;
2722 }
2723 close(fileHandle);
2724 }
2725 }
2726 } else
2727 {
2728 // floppy case
2729 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2730 {
2731 /// @todo do some more testing, maybe a nice IOCTL!
2732 retValue = true;
2733 }
2734 }
2735 }
2736 return retValue;
2737}
2738#endif // RT_OS_SOLARIS
2739
2740#ifdef VBOX_WITH_USB
2741/**
2742 * Checks for the presence and status of the USB Proxy Service.
2743 * Returns S_OK when the Proxy is present and OK, VBOX_E_HOST_ERROR (as a
2744 * warning) if the proxy service is not available due to the way the host is
2745 * configured (at present, that means that usbfs and hal/DBus are not
2746 * available on a Linux host) or E_FAIL and a corresponding error message
2747 * otherwise. Intended to be used by methods that rely on the Proxy Service
2748 * availability.
2749 *
2750 * @note This method may return a warning result code. It is recommended to use
2751 * MultiError to store the return value.
2752 *
2753 * @note Locks this object for reading.
2754 */
2755HRESULT Host::checkUSBProxyService()
2756{
2757 AutoCaller autoCaller(this);
2758 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2759
2760 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2761
2762 AssertReturn(m->pUSBProxyService, E_FAIL);
2763 if (!m->pUSBProxyService->isActive())
2764 {
2765 /* disable the USB controller completely to avoid assertions if the
2766 * USB proxy service could not start. */
2767
2768 switch (m->pUSBProxyService->getLastError())
2769 {
2770 case VERR_FILE_NOT_FOUND: /** @todo what does this mean? */
2771 return setWarning(E_FAIL,
2772 tr("Could not load the Host USB Proxy Service (VERR_FILE_NOT_FOUND). The service might not be installed on the host computer"));
2773 case VERR_VUSB_USB_DEVICE_PERMISSION:
2774 return setWarning(E_FAIL,
2775 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"));
2776 case VERR_VUSB_USBFS_PERMISSION:
2777 return setWarning(E_FAIL,
2778 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"));
2779 case VINF_SUCCESS:
2780 return setWarning(E_FAIL,
2781 tr("The USB Proxy Service has not yet been ported to this host"));
2782 default:
2783 return setWarning (E_FAIL, "%s: %Rrc",
2784 tr ("Could not load the Host USB Proxy service"),
2785 m->pUSBProxyService->getLastError());
2786 }
2787 }
2788
2789 return S_OK;
2790}
2791#endif /* VBOX_WITH_USB */
2792
2793#ifdef VBOX_WITH_RESOURCE_USAGE_API
2794
2795void Host::registerMetrics(PerformanceCollector *aCollector)
2796{
2797 pm::CollectorHAL *hal = aCollector->getHAL();
2798 /* Create sub metrics */
2799 pm::SubMetric *cpuLoadUser = new pm::SubMetric("CPU/Load/User",
2800 "Percentage of processor time spent in user mode.");
2801 pm::SubMetric *cpuLoadKernel = new pm::SubMetric("CPU/Load/Kernel",
2802 "Percentage of processor time spent in kernel mode.");
2803 pm::SubMetric *cpuLoadIdle = new pm::SubMetric("CPU/Load/Idle",
2804 "Percentage of processor time spent idling.");
2805 pm::SubMetric *cpuMhzSM = new pm::SubMetric("CPU/MHz",
2806 "Average of current frequency of all processors.");
2807 pm::SubMetric *ramUsageTotal = new pm::SubMetric("RAM/Usage/Total",
2808 "Total physical memory installed.");
2809 pm::SubMetric *ramUsageUsed = new pm::SubMetric("RAM/Usage/Used",
2810 "Physical memory currently occupied.");
2811 pm::SubMetric *ramUsageFree = new pm::SubMetric("RAM/Usage/Free",
2812 "Physical memory currently available to applications.");
2813 pm::SubMetric *ramVMMUsed = new pm::SubMetric("RAM/VMM/Used",
2814 "Total physical memory used by the hypervisor.");
2815 pm::SubMetric *ramVMMFree = new pm::SubMetric("RAM/VMM/Free",
2816 "Total physical memory free inside the hypervisor.");
2817 pm::SubMetric *ramVMMBallooned = new pm::SubMetric("RAM/VMM/Ballooned",
2818 "Total physical memory ballooned by the hypervisor.");
2819 pm::SubMetric *ramVMMShared = new pm::SubMetric("RAM/VMM/Shared",
2820 "Total physical memory shared between VMs.");
2821
2822
2823 /* Create and register base metrics */
2824 IUnknown *objptr;
2825 ComObjPtr<Host> tmp = this;
2826 tmp.queryInterfaceTo(&objptr);
2827 pm::BaseMetric *cpuLoad = new pm::HostCpuLoadRaw(hal, objptr, cpuLoadUser, cpuLoadKernel,
2828 cpuLoadIdle);
2829 aCollector->registerBaseMetric (cpuLoad);
2830 pm::BaseMetric *cpuMhz = new pm::HostCpuMhz(hal, objptr, cpuMhzSM);
2831 aCollector->registerBaseMetric (cpuMhz);
2832 pm::BaseMetric *ramUsage = new pm::HostRamUsage(hal, objptr,
2833 ramUsageTotal,
2834 ramUsageUsed,
2835 ramUsageFree);
2836 aCollector->registerBaseMetric (ramUsage);
2837 pm::BaseMetric *ramVmm = new pm::HostRamVmm(aCollector->getGuestManager(), objptr,
2838 ramVMMUsed,
2839 ramVMMFree,
2840 ramVMMBallooned,
2841 ramVMMShared);
2842 aCollector->registerBaseMetric (ramVmm);
2843
2844 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser, 0));
2845 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
2846 new pm::AggregateAvg()));
2847 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
2848 new pm::AggregateMin()));
2849 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
2850 new pm::AggregateMax()));
2851
2852 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel, 0));
2853 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
2854 new pm::AggregateAvg()));
2855 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
2856 new pm::AggregateMin()));
2857 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
2858 new pm::AggregateMax()));
2859
2860 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle, 0));
2861 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
2862 new pm::AggregateAvg()));
2863 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
2864 new pm::AggregateMin()));
2865 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
2866 new pm::AggregateMax()));
2867
2868 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM, 0));
2869 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
2870 new pm::AggregateAvg()));
2871 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
2872 new pm::AggregateMin()));
2873 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
2874 new pm::AggregateMax()));
2875
2876 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal, 0));
2877 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
2878 new pm::AggregateAvg()));
2879 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
2880 new pm::AggregateMin()));
2881 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
2882 new pm::AggregateMax()));
2883
2884 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed, 0));
2885 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
2886 new pm::AggregateAvg()));
2887 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
2888 new pm::AggregateMin()));
2889 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
2890 new pm::AggregateMax()));
2891
2892 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree, 0));
2893 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
2894 new pm::AggregateAvg()));
2895 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
2896 new pm::AggregateMin()));
2897 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
2898 new pm::AggregateMax()));
2899
2900 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed, 0));
2901 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
2902 new pm::AggregateAvg()));
2903 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
2904 new pm::AggregateMin()));
2905 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
2906 new pm::AggregateMax()));
2907
2908 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree, 0));
2909 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
2910 new pm::AggregateAvg()));
2911 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
2912 new pm::AggregateMin()));
2913 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
2914 new pm::AggregateMax()));
2915
2916 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned, 0));
2917 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
2918 new pm::AggregateAvg()));
2919 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
2920 new pm::AggregateMin()));
2921 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
2922 new pm::AggregateMax()));
2923
2924 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared, 0));
2925 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
2926 new pm::AggregateAvg()));
2927 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
2928 new pm::AggregateMin()));
2929 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
2930 new pm::AggregateMax()));
2931}
2932
2933void Host::unregisterMetrics (PerformanceCollector *aCollector)
2934{
2935 aCollector->unregisterMetricsFor(this);
2936 aCollector->unregisterBaseMetricsFor(this);
2937}
2938
2939
2940/* static */
2941void Host::generateMACAddress(Utf8Str &mac)
2942{
2943 /*
2944 * Our strategy is as follows: the first three bytes are our fixed
2945 * vendor ID (080027). The remaining 3 bytes will be taken from the
2946 * start of a GUID. This is a fairly safe algorithm.
2947 */
2948 Guid guid;
2949 guid.create();
2950 mac = Utf8StrFmt("080027%02X%02X%02X",
2951 guid.raw()->au8[0], guid.raw()->au8[1], guid.raw()->au8[2]);
2952}
2953
2954#endif /* VBOX_WITH_RESOURCE_USAGE_API */
2955
2956/* 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