VirtualBox

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

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

Main/HostUSBDevice(all platforms)+USBProxyService: redo USB locking, fixes major regression, added lots of assertions to catch locking flaws early, whitespace cleanup
Main/Machine: small USB locking fix to be consistent with the remaining code
Main/Host+glue/AutoLock: replace USB list lock by host lock, small numbering cleanup
Main/Console: redo USB locking, do less in USB callbacks/EMT (addresses long standing todo items), eliminate unsafe iterator parameters

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