VirtualBox

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

Last change on this file since 25877 was 25860, checked in by vboxsync, 15 years ago

Main: cleanup: get rid of VirtualBoxBaseProto, move AutoCaller*/*Span* classes out of VirtualBoxBaseProto class scope and into separate header; move CombinedProgress into separate header (it's only used by Console any more)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 83.3 KB
Line 
1/* $Id: HostImpl.cpp 25860 2010-01-15 13:27:26Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation: Host
4 */
5
6/*
7 * Copyright (C) 2006-2009 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22#define __STDC_LIMIT_MACROS
23#define __STDC_CONSTANT_MACROS
24
25#ifdef VBOX_WITH_USB
26# include "HostUSBDeviceImpl.h"
27# include "USBDeviceFilterImpl.h"
28# include "USBProxyService.h"
29# include "VirtualBoxImpl.h"
30#endif // VBOX_WITH_USB
31
32#include "MediumImpl.h"
33#include "HostPower.h"
34
35#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
36# include <HostHardwareLinux.h>
37#endif
38
39#ifdef VBOX_WITH_RESOURCE_USAGE_API
40# include "PerformanceImpl.h"
41#endif /* VBOX_WITH_RESOURCE_USAGE_API */
42
43#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
44# include <VBox/WinNetConfig.h>
45#endif /* #if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT) */
46
47#ifdef RT_OS_LINUX
48# include <sys/ioctl.h>
49# include <errno.h>
50# include <net/if.h>
51# include <net/if_arp.h>
52#endif /* RT_OS_LINUX */
53
54#ifdef RT_OS_SOLARIS
55# include <fcntl.h>
56# include <unistd.h>
57# include <stropts.h>
58# include <errno.h>
59# include <limits.h>
60# include <stdio.h>
61# ifdef VBOX_SOLARIS_NSL_RESOLVED
62# include <libdevinfo.h>
63# endif
64# include <net/if.h>
65# include <sys/socket.h>
66# include <sys/sockio.h>
67# include <net/if_arp.h>
68# include <net/if.h>
69# include <sys/types.h>
70# include <sys/stat.h>
71# include <sys/cdio.h>
72# include <sys/dkio.h>
73# include <sys/mnttab.h>
74# include <sys/mntent.h>
75/* Dynamic loading of libhal on Solaris hosts */
76# ifdef VBOX_USE_LIBHAL
77# include "vbox-libhal.h"
78extern "C" char *getfullrawname(char *);
79# endif
80# include "solaris/DynLoadLibSolaris.h"
81#endif /* RT_OS_SOLARIS */
82
83#ifdef RT_OS_WINDOWS
84# define _WIN32_DCOM
85# include <windows.h>
86# include <shellapi.h>
87# define INITGUID
88# include <guiddef.h>
89# include <devguid.h>
90# include <objbase.h>
91//# include <setupapi.h>
92# include <shlobj.h>
93# include <cfgmgr32.h>
94
95#endif /* RT_OS_WINDOWS */
96
97#include "HostImpl.h"
98#include "HostNetworkInterfaceImpl.h"
99#ifdef VBOX_WITH_USB
100# include "HostUSBDeviceImpl.h"
101# include "USBDeviceFilterImpl.h"
102# include "USBProxyService.h"
103#endif
104#include "VirtualBoxImpl.h"
105#include "MachineImpl.h"
106#include "AutoCaller.h"
107#include "Logging.h"
108#include "Performance.h"
109
110#ifdef RT_OS_DARWIN
111# include "darwin/iokit.h"
112#endif
113
114#ifdef VBOX_WITH_CROGL
115extern bool is3DAccelerationSupported();
116#endif /* VBOX_WITH_CROGL */
117
118#include <iprt/asm.h>
119#include <iprt/string.h>
120#include <iprt/mp.h>
121#include <iprt/time.h>
122#include <iprt/param.h>
123#include <iprt/env.h>
124#include <iprt/mem.h>
125#include <iprt/system.h>
126#ifdef RT_OS_SOLARIS
127# include <iprt/path.h>
128# include <iprt/ctype.h>
129#endif
130#ifdef VBOX_WITH_HOSTNETIF_API
131#include "netif.h"
132#endif
133
134#include <VBox/usb.h>
135#include <VBox/x86.h>
136#include <VBox/err.h>
137#include <VBox/settings.h>
138#include <VBox/sup.h>
139
140#include <stdio.h>
141
142#include <algorithm>
143
144
145////////////////////////////////////////////////////////////////////////////////
146//
147// Host private data definition
148//
149////////////////////////////////////////////////////////////////////////////////
150
151struct Host::Data
152{
153 Data()
154#ifdef VBOX_WITH_USB
155 : usbListsLock(LOCKCLASS_USBLIST)
156#endif
157 {};
158
159 ComObjPtr<VirtualBox, ComWeakRef>
160 pParent;
161
162#ifdef VBOX_WITH_USB
163 WriteLockHandle usbListsLock; // protects the below two lists
164
165 USBDeviceFilterList llChildren; // all USB device filters
166 USBDeviceFilterList llUSBDeviceFilters; // USB device filters in use by the USB proxy service
167
168 /** Pointer to the USBProxyService object. */
169 USBProxyService *pUSBProxyService;
170#endif /* VBOX_WITH_USB */
171
172#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
173 /** Object with information about host drives */
174 VBoxMainDriveInfo hostDrives;
175#endif
176 /* Features that can be queried with GetProcessorFeature */
177 BOOL fVTSupported,
178 fLongModeSupported,
179 fPAESupported,
180 fNestedPagingSupported;
181
182 /* 3D hardware acceleration supported? */
183 BOOL f3DAccelerationSupported;
184
185 HostPowerService *pHostPowerService;
186};
187
188
189////////////////////////////////////////////////////////////////////////////////
190//
191// Constructor / destructor
192//
193////////////////////////////////////////////////////////////////////////////////
194
195HRESULT Host::FinalConstruct()
196{
197 return S_OK;
198}
199
200void Host::FinalRelease()
201{
202 uninit();
203}
204
205/**
206 * Initializes the host object.
207 *
208 * @param aParent VirtualBox parent object.
209 */
210HRESULT Host::init(VirtualBox *aParent)
211{
212 LogFlowThisFunc(("aParent=%p\n", aParent));
213
214 /* Enclose the state transition NotReady->InInit->Ready */
215 AutoInitSpan autoInitSpan(this);
216 AssertReturn(autoInitSpan.isOk(), E_FAIL);
217
218 m = new Data();
219
220 m->pParent = aParent;
221
222#ifdef VBOX_WITH_USB
223 /*
224 * Create and initialize the USB Proxy Service.
225 */
226# if defined (RT_OS_DARWIN)
227 m->pUSBProxyService = new USBProxyServiceDarwin (this);
228# elif defined (RT_OS_LINUX)
229 m->pUSBProxyService = new USBProxyServiceLinux (this);
230# elif defined (RT_OS_OS2)
231 m->pUSBProxyService = new USBProxyServiceOs2 (this);
232# elif defined (RT_OS_SOLARIS)
233 m->pUSBProxyService = new USBProxyServiceSolaris (this);
234# elif defined (RT_OS_WINDOWS)
235 m->pUSBProxyService = new USBProxyServiceWindows (this);
236# elif defined (RT_OS_FREEBSD)
237 m->pUSBProxyService = new USBProxyServiceFreeBSD (this);
238# else
239 m->pUSBProxyService = new USBProxyService (this);
240# endif
241 HRESULT hrc = m->pUSBProxyService->init();
242 AssertComRCReturn(hrc, hrc);
243#endif /* VBOX_WITH_USB */
244
245#ifdef VBOX_WITH_RESOURCE_USAGE_API
246 registerMetrics(aParent->performanceCollector());
247#endif /* VBOX_WITH_RESOURCE_USAGE_API */
248
249#if defined (RT_OS_WINDOWS)
250 m->pHostPowerService = new HostPowerServiceWin (m->pParent);
251#elif defined (RT_OS_DARWIN)
252 m->pHostPowerService = new HostPowerServiceDarwin (m->pParent);
253#else
254 m->pHostPowerService = new HostPowerService (m->pParent);
255#endif
256
257 /* Cache the features reported by GetProcessorFeature. */
258 m->fVTSupported = false;
259 m->fLongModeSupported = false;
260 m->fPAESupported = false;
261 m->fNestedPagingSupported = false;
262
263 if (ASMHasCpuId())
264 {
265 uint32_t u32FeaturesECX;
266 uint32_t u32Dummy;
267 uint32_t u32FeaturesEDX;
268 uint32_t u32VendorEBX, u32VendorECX, u32VendorEDX, u32AMDFeatureEDX, u32AMDFeatureECX;
269
270 ASMCpuId(0, &u32Dummy, &u32VendorEBX, &u32VendorECX, &u32VendorEDX);
271 ASMCpuId(1, &u32Dummy, &u32Dummy, &u32FeaturesECX, &u32FeaturesEDX);
272 /* Query AMD features. */
273 ASMCpuId(0x80000001, &u32Dummy, &u32Dummy, &u32AMDFeatureECX, &u32AMDFeatureEDX);
274
275 m->fLongModeSupported = !!(u32AMDFeatureEDX & X86_CPUID_AMD_FEATURE_EDX_LONG_MODE);
276 m->fPAESupported = !!(u32FeaturesEDX & X86_CPUID_FEATURE_EDX_PAE);
277
278 if ( u32VendorEBX == X86_CPUID_VENDOR_INTEL_EBX
279 && u32VendorECX == X86_CPUID_VENDOR_INTEL_ECX
280 && u32VendorEDX == X86_CPUID_VENDOR_INTEL_EDX
281 )
282 {
283 if ( (u32FeaturesECX & X86_CPUID_FEATURE_ECX_VMX)
284 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR)
285 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR)
286 )
287 {
288 int rc = SUPR3QueryVTxSupported();
289 if (RT_SUCCESS(rc))
290 m->fVTSupported = true;
291 }
292 }
293 else
294 if ( u32VendorEBX == X86_CPUID_VENDOR_AMD_EBX
295 && u32VendorECX == X86_CPUID_VENDOR_AMD_ECX
296 && u32VendorEDX == X86_CPUID_VENDOR_AMD_EDX
297 )
298 {
299 if ( (u32AMDFeatureECX & X86_CPUID_AMD_FEATURE_ECX_SVM)
300 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR)
301 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR)
302 )
303 m->fVTSupported = true;
304 }
305 }
306
307#if 0 /* needs testing */
308 if (m->fVTSupported)
309 {
310 uint32_t u32Caps = 0;
311
312 int rc = SUPR3QueryVTCaps(&u32Caps);
313 if (VBOX_SUCCESS(rc))
314 {
315 if (u32Caps & SUPVTCAPS_NESTED_PAGING)
316 m->fNestedPagingSupported = true;
317 }
318 /* else @todo; report BIOS trouble in some way. */
319 }
320#endif
321
322 /* Test for 3D hardware acceleration support */
323 m->f3DAccelerationSupported = false;
324
325#ifdef VBOX_WITH_CROGL
326 m->f3DAccelerationSupported = is3DAccelerationSupported();
327#endif /* VBOX_WITH_CROGL */
328
329 /* Confirm a successful initialization */
330 autoInitSpan.setSucceeded();
331
332 return S_OK;
333}
334
335/**
336 * Uninitializes the host object and sets the ready flag to FALSE.
337 * Called either from FinalRelease() or by the parent when it gets destroyed.
338 */
339void Host::uninit()
340{
341 LogFlowThisFunc(("\n"));
342
343 /* Enclose the state transition Ready->InUninit->NotReady */
344 AutoUninitSpan autoUninitSpan(this);
345 if (autoUninitSpan.uninitDone())
346 return;
347
348#ifdef VBOX_WITH_RESOURCE_USAGE_API
349 unregisterMetrics (m->pParent->performanceCollector());
350#endif /* VBOX_WITH_RESOURCE_USAGE_API */
351
352#ifdef VBOX_WITH_USB
353 /* wait for USB proxy service to terminate before we uninit all USB
354 * devices */
355 LogFlowThisFunc(("Stopping USB proxy service...\n"));
356 delete m->pUSBProxyService;
357 m->pUSBProxyService = NULL;
358 LogFlowThisFunc(("Done stopping USB proxy service.\n"));
359#endif
360
361 delete m->pHostPowerService;
362
363#ifdef VBOX_WITH_USB
364 /* uninit all USB device filters still referenced by clients
365 * Note! HostUSBDeviceFilter::uninit() will modify llChildren. */
366 while (!m->llChildren.empty())
367 {
368 ComObjPtr<HostUSBDeviceFilter> &pChild = m->llChildren.front();
369 pChild->uninit();
370 }
371
372 m->llUSBDeviceFilters.clear();
373#endif
374
375 delete m;
376 m = NULL;
377}
378
379////////////////////////////////////////////////////////////////////////////////
380//
381// ISnapshot public methods
382//
383////////////////////////////////////////////////////////////////////////////////
384
385/**
386 * Returns a list of host DVD drives.
387 *
388 * @returns COM status code
389 * @param drives address of result pointer
390 */
391STDMETHODIMP Host::COMGETTER(DVDDrives)(ComSafeArrayOut(IMedium *, aDrives))
392{
393 CheckComArgOutSafeArrayPointerValid(aDrives);
394
395 AutoCaller autoCaller(this);
396 if (FAILED(autoCaller.rc())) return autoCaller.rc();
397
398 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
399
400 MediaList list;
401 HRESULT rc = S_OK;
402 try
403 {
404#if defined(RT_OS_WINDOWS)
405 int sz = GetLogicalDriveStrings(0, NULL);
406 TCHAR *hostDrives = new TCHAR[sz+1];
407 GetLogicalDriveStrings(sz, hostDrives);
408 wchar_t driveName[3] = { '?', ':', '\0' };
409 TCHAR *p = hostDrives;
410 do
411 {
412 if (GetDriveType(p) == DRIVE_CDROM)
413 {
414 driveName[0] = *p;
415 ComObjPtr<Medium> hostDVDDriveObj;
416 hostDVDDriveObj.createObject();
417 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(driveName));
418 list.push_back(hostDVDDriveObj);
419 }
420 p += _tcslen(p) + 1;
421 }
422 while (*p);
423 delete[] hostDrives;
424
425#elif defined(RT_OS_SOLARIS)
426# ifdef VBOX_USE_LIBHAL
427 if (!getDVDInfoFromHal(list))
428# endif
429 // Not all Solaris versions ship with libhal.
430 // So use a fallback approach similar to Linux.
431 {
432 if (RTEnvGet("VBOX_CDROM"))
433 {
434 char *cdromEnv = strdup(RTEnvGet("VBOX_CDROM"));
435 char *saveStr = NULL;
436 char *cdromDrive = NULL;
437 if (cdromEnv)
438 cdromDrive = strtok_r(cdromEnv, ":", &saveStr);
439 while (cdromDrive)
440 {
441 if (validateDevice(cdromDrive, true))
442 {
443 ComObjPtr<Medium> hostDVDDriveObj;
444 hostDVDDriveObj.createObject();
445 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(cdromDrive));
446 list.push_back(hostDVDDriveObj);
447 }
448 cdromDrive = strtok_r(NULL, ":", &saveStr);
449 }
450 free(cdromEnv);
451 }
452 else
453 {
454 // this might work on Solaris version older than Nevada.
455 if (validateDevice("/cdrom/cdrom0", true))
456 {
457 ComObjPtr<Medium> hostDVDDriveObj;
458 hostDVDDriveObj.createObject();
459 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr("cdrom/cdrom0"));
460 list.push_back(hostDVDDriveObj);
461 }
462
463 // check the mounted drives
464 parseMountTable(MNTTAB, list);
465 }
466 }
467
468#elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
469 if (RT_SUCCESS(m->hostDrives.updateDVDs()))
470 for (DriveInfoList::const_iterator it = m->hostDrives.DVDBegin();
471 SUCCEEDED(rc) && it != m->hostDrives.DVDEnd(); ++it)
472 {
473 ComObjPtr<Medium> hostDVDDriveObj;
474 Bstr location(it->mDevice);
475 Bstr description(it->mDescription);
476 if (SUCCEEDED(rc))
477 rc = hostDVDDriveObj.createObject();
478 if (SUCCEEDED(rc))
479 rc = hostDVDDriveObj->init(m->pParent, DeviceType_DVD, location, description);
480 if (SUCCEEDED(rc))
481 list.push_back(hostDVDDriveObj);
482 }
483#elif defined(RT_OS_DARWIN)
484 PDARWINDVD cur = DarwinGetDVDDrives();
485 while (cur)
486 {
487 ComObjPtr<Medium> hostDVDDriveObj;
488 hostDVDDriveObj.createObject();
489 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(cur->szName));
490 list.push_back(hostDVDDriveObj);
491
492 /* next */
493 void *freeMe = cur;
494 cur = cur->pNext;
495 RTMemFree(freeMe);
496 }
497#else
498 /* PORTME */
499#endif
500
501 SafeIfaceArray<IMedium> array(list);
502 array.detachTo(ComSafeArrayOutArg(aDrives));
503 }
504 catch(std::bad_alloc &)
505 {
506 rc = E_OUTOFMEMORY;
507 }
508 return rc;
509}
510
511/**
512 * Returns a list of host floppy drives.
513 *
514 * @returns COM status code
515 * @param drives address of result pointer
516 */
517STDMETHODIMP Host::COMGETTER(FloppyDrives)(ComSafeArrayOut(IMedium *, aDrives))
518{
519 CheckComArgOutPointerValid(aDrives);
520
521 AutoCaller autoCaller(this);
522 if (FAILED(autoCaller.rc())) return autoCaller.rc();
523
524 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
525
526 MediaList list;
527 HRESULT rc = S_OK;
528
529 try
530 {
531#ifdef RT_OS_WINDOWS
532 int sz = GetLogicalDriveStrings(0, NULL);
533 TCHAR *hostDrives = new TCHAR[sz+1];
534 GetLogicalDriveStrings(sz, hostDrives);
535 wchar_t driveName[3] = { '?', ':', '\0' };
536 TCHAR *p = hostDrives;
537 do
538 {
539 if (GetDriveType(p) == DRIVE_REMOVABLE)
540 {
541 driveName[0] = *p;
542 ComObjPtr<Medium> hostFloppyDriveObj;
543 hostFloppyDriveObj.createObject();
544 hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, Bstr(driveName));
545 list.push_back(hostFloppyDriveObj);
546 }
547 p += _tcslen(p) + 1;
548 }
549 while (*p);
550 delete[] hostDrives;
551#elif defined(RT_OS_LINUX)
552 if (RT_SUCCESS(m->hostDrives.updateFloppies()))
553 for (DriveInfoList::const_iterator it = m->hostDrives.FloppyBegin();
554 SUCCEEDED(rc) && it != m->hostDrives.FloppyEnd(); ++it)
555 {
556 ComObjPtr<Medium> hostFloppyDriveObj;
557 Bstr location(it->mDevice);
558 Bstr description(it->mDescription);
559 if (SUCCEEDED(rc))
560 rc = hostFloppyDriveObj.createObject();
561 if (SUCCEEDED(rc))
562 rc = hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, location, description);
563 if (SUCCEEDED(rc))
564 list.push_back(hostFloppyDriveObj);
565 }
566#else
567 /* PORTME */
568#endif
569
570 SafeIfaceArray<IMedium> collection(list);
571 collection.detachTo(ComSafeArrayOutArg(aDrives));
572 }
573 catch(std::bad_alloc &)
574 {
575 rc = E_OUTOFMEMORY;
576 }
577 return rc;
578}
579
580
581#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
582# define VBOX_APP_NAME L"VirtualBox"
583
584static int vboxNetWinAddComponent(std::list< ComObjPtr<HostNetworkInterface> > *pPist,
585 INetCfgComponent *pncc)
586{
587 LPWSTR lpszName;
588 GUID IfGuid;
589 HRESULT hr;
590 int rc = VERR_GENERAL_FAILURE;
591
592 hr = pncc->GetDisplayName( &lpszName );
593 Assert(hr == S_OK);
594 if(hr == S_OK)
595 {
596 size_t cUnicodeName = wcslen(lpszName) + 1;
597 size_t uniLen = (cUnicodeName * 2 + sizeof (OLECHAR) - 1) / sizeof (OLECHAR);
598 Bstr name (uniLen + 1 /* extra zero */);
599 wcscpy((wchar_t *) name.mutableRaw(), lpszName);
600
601 hr = pncc->GetInstanceGuid(&IfGuid);
602 Assert(hr == S_OK);
603 if (hr == S_OK)
604 {
605 /* create a new object and add it to the list */
606 ComObjPtr<HostNetworkInterface> iface;
607 iface.createObject();
608 /* remove the curly bracket at the end */
609 if (SUCCEEDED(iface->init (name, Guid (IfGuid), HostNetworkInterfaceType_Bridged)))
610 {
611// iface->setVirtualBox(m->pParent);
612 pPist->push_back(iface);
613 rc = VINF_SUCCESS;
614 }
615 else
616 {
617 Assert(0);
618 }
619 }
620 CoTaskMemFree(lpszName);
621 }
622
623 return rc;
624}
625#endif /* defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT) */
626
627/**
628 * Returns a list of host network interfaces.
629 *
630 * @returns COM status code
631 * @param drives address of result pointer
632 */
633STDMETHODIMP Host::COMGETTER(NetworkInterfaces)(ComSafeArrayOut(IHostNetworkInterface*, aNetworkInterfaces))
634{
635#if defined(RT_OS_WINDOWS) || defined(VBOX_WITH_NETFLT) /*|| defined(RT_OS_OS2)*/
636 if (ComSafeArrayOutIsNull(aNetworkInterfaces))
637 return E_POINTER;
638
639 AutoCaller autoCaller(this);
640 if (FAILED(autoCaller.rc())) return autoCaller.rc();
641
642 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
643
644 std::list <ComObjPtr<HostNetworkInterface> > list;
645
646# ifdef VBOX_WITH_HOSTNETIF_API
647 int rc = NetIfList(list);
648 if (rc)
649 {
650 Log(("Failed to get host network interface list with rc=%Vrc\n", rc));
651 }
652# else
653
654# if defined(RT_OS_DARWIN)
655 PDARWINETHERNIC pEtherNICs = DarwinGetEthernetControllers();
656 while (pEtherNICs)
657 {
658 ComObjPtr<HostNetworkInterface> IfObj;
659 IfObj.createObject();
660 if (SUCCEEDED(IfObj->init(Bstr(pEtherNICs->szName), Guid(pEtherNICs->Uuid), HostNetworkInterfaceType_Bridged)))
661 list.push_back(IfObj);
662
663 /* next, free current */
664 void *pvFree = pEtherNICs;
665 pEtherNICs = pEtherNICs->pNext;
666 RTMemFree(pvFree);
667 }
668
669# elif defined(RT_OS_SOLARIS)
670
671# ifdef VBOX_SOLARIS_NSL_RESOLVED
672
673 /*
674 * Use libdevinfo for determining all physical interfaces.
675 */
676 di_node_t Root;
677 Root = di_init("/", DINFOCACHE);
678 if (Root != DI_NODE_NIL)
679 {
680 di_walk_minor(Root, DDI_NT_NET, 0, &list, vboxSolarisAddPhysHostIface);
681 di_fini(Root);
682 }
683
684 /*
685 * Use libdlpi for determining all DLPI interfaces.
686 */
687 if (VBoxSolarisLibDlpiFound())
688 g_pfnLibDlpiWalk(vboxSolarisAddLinkHostIface, &list, 0);
689
690# endif /* VBOX_SOLARIS_NSL_RESOLVED */
691
692 /*
693 * This gets only the list of all plumbed logical interfaces.
694 * This is needed for zones which cannot access the device tree
695 * and in this case we just let them use the list of plumbed interfaces
696 * on the zone.
697 */
698 int Sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
699 if (Sock > 0)
700 {
701 struct lifnum IfNum;
702 memset(&IfNum, 0, sizeof(IfNum));
703 IfNum.lifn_family = AF_INET;
704 int rc = ioctl(Sock, SIOCGLIFNUM, &IfNum);
705 if (!rc)
706 {
707 struct lifreq Ifaces[24];
708 struct lifconf IfConfig;
709 memset(&IfConfig, 0, sizeof(IfConfig));
710 IfConfig.lifc_family = AF_INET;
711 IfConfig.lifc_len = sizeof(Ifaces);
712 IfConfig.lifc_buf = (caddr_t)&(Ifaces[0]);
713 rc = ioctl(Sock, SIOCGLIFCONF, &IfConfig);
714 if (!rc)
715 {
716 for (int i = 0; i < IfNum.lifn_count; i++)
717 {
718 /*
719 * Skip loopback interfaces.
720 */
721 if (!strncmp(Ifaces[i].lifr_name, "lo", 2))
722 continue;
723
724#if 0
725 rc = ioctl(Sock, SIOCGLIFADDR, &(Ifaces[i]));
726 if (!rc)
727 {
728 RTMAC Mac;
729 struct arpreq ArpReq;
730 memcpy(&ArpReq.arp_pa, &Ifaces[i].lifr_addr, sizeof(struct sockaddr_in));
731
732 /*
733 * We might fail if the interface has not been assigned an IP address.
734 * That doesn't matter; as long as it's plumbed we can pick it up.
735 * But, if it has not acquired an IP address we cannot obtain it's MAC
736 * address this way, so we just use all zeros there.
737 */
738 rc = ioctl(Sock, SIOCGARP, &ArpReq);
739 if (!rc)
740 memcpy(&Mac, ArpReq.arp_ha.sa_data, sizeof(RTMAC));
741 else
742 memset(&Mac, 0, sizeof(Mac));
743
744 char szNICDesc[LIFNAMSIZ + 256];
745 char *pszIface = Ifaces[i].lifr_name;
746 strcpy(szNICDesc, pszIface);
747
748 vboxSolarisAddLinkHostIface(pszIface, &list);
749 }
750#endif
751
752 char *pszIface = Ifaces[i].lifr_name;
753 vboxSolarisAddLinkHostIface(pszIface, &list);
754 }
755 }
756 }
757 close(Sock);
758 }
759
760 /*
761 * Weed out duplicates caused by dlpi_walk inconsistencies across Nevadas.
762 */
763 list.sort(vboxSolarisSortNICList);
764 list.unique(vboxSolarisSameNIC);
765
766# elif defined RT_OS_WINDOWS
767# ifndef VBOX_WITH_NETFLT
768 hr = E_NOTIMPL;
769# else /* # if defined VBOX_WITH_NETFLT */
770 INetCfg *pNc;
771 INetCfgComponent *pMpNcc;
772 INetCfgComponent *pTcpIpNcc;
773 LPWSTR lpszApp;
774 HRESULT hr;
775 IEnumNetCfgBindingPath *pEnumBp;
776 INetCfgBindingPath *pBp;
777 IEnumNetCfgBindingInterface *pEnumBi;
778 INetCfgBindingInterface *pBi;
779
780 /* we are using the INetCfg API for getting the list of miniports */
781 hr = VBoxNetCfgWinQueryINetCfg( FALSE,
782 VBOX_APP_NAME,
783 &pNc,
784 &lpszApp );
785 Assert(hr == S_OK);
786 if(hr == S_OK)
787 {
788# ifdef VBOX_NETFLT_ONDEMAND_BIND
789 /* for the protocol-based approach for now we just get all miniports the MS_TCPIP protocol binds to */
790 hr = pNc->FindComponent(L"MS_TCPIP", &pTcpIpNcc);
791# else
792 /* for the filter-based approach we get all miniports our filter (sun_VBoxNetFlt)is bound to */
793 hr = pNc->FindComponent(L"sun_VBoxNetFlt", &pTcpIpNcc);
794# ifndef VBOX_WITH_HARDENING
795 if(hr != S_OK)
796 {
797 /* TODO: try to install the netflt from here */
798 }
799# endif
800
801# endif
802
803 if(hr == S_OK)
804 {
805 hr = VBoxNetCfgWinGetBindingPathEnum(pTcpIpNcc, EBP_BELOW, &pEnumBp);
806 Assert(hr == S_OK);
807 if ( hr == S_OK )
808 {
809 hr = VBoxNetCfgWinGetFirstBindingPath(pEnumBp, &pBp);
810 Assert(hr == S_OK || hr == S_FALSE);
811 while( hr == S_OK )
812 {
813 /* S_OK == enabled, S_FALSE == disabled */
814 if(pBp->IsEnabled() == S_OK)
815 {
816 hr = VBoxNetCfgWinGetBindingInterfaceEnum(pBp, &pEnumBi);
817 Assert(hr == S_OK);
818 if ( hr == S_OK )
819 {
820 hr = VBoxNetCfgWinGetFirstBindingInterface(pEnumBi, &pBi);
821 Assert(hr == S_OK);
822 while(hr == S_OK)
823 {
824 hr = pBi->GetLowerComponent( &pMpNcc );
825 Assert(hr == S_OK);
826 if(hr == S_OK)
827 {
828 ULONG uComponentStatus;
829 hr = pMpNcc->GetDeviceStatus(&uComponentStatus);
830 Assert(hr == S_OK);
831 if(hr == S_OK)
832 {
833 if(uComponentStatus == 0)
834 {
835 vboxNetWinAddComponent(&list, pMpNcc);
836 }
837 }
838 VBoxNetCfgWinReleaseRef( pMpNcc );
839 }
840 VBoxNetCfgWinReleaseRef(pBi);
841
842 hr = VBoxNetCfgWinGetNextBindingInterface(pEnumBi, &pBi);
843 }
844 VBoxNetCfgWinReleaseRef(pEnumBi);
845 }
846 }
847 VBoxNetCfgWinReleaseRef(pBp);
848
849 hr = VBoxNetCfgWinGetNextBindingPath(pEnumBp, &pBp);
850 }
851 VBoxNetCfgWinReleaseRef(pEnumBp);
852 }
853 VBoxNetCfgWinReleaseRef(pTcpIpNcc);
854 }
855 else
856 {
857 LogRel(("failed to get the sun_VBoxNetFlt component, error (0x%x)", hr));
858 }
859
860 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE);
861 }
862# endif /* # if defined VBOX_WITH_NETFLT */
863
864
865# elif defined RT_OS_LINUX
866 int sock = socket(AF_INET, SOCK_DGRAM, 0);
867 if (sock >= 0)
868 {
869 char pBuffer[2048];
870 struct ifconf ifConf;
871 ifConf.ifc_len = sizeof(pBuffer);
872 ifConf.ifc_buf = pBuffer;
873 if (ioctl(sock, SIOCGIFCONF, &ifConf) >= 0)
874 {
875 for (struct ifreq *pReq = ifConf.ifc_req; (char*)pReq < pBuffer + ifConf.ifc_len; pReq++)
876 {
877 if (ioctl(sock, SIOCGIFHWADDR, pReq) >= 0)
878 {
879 if (pReq->ifr_hwaddr.sa_family == ARPHRD_ETHER)
880 {
881 RTUUID uuid;
882 Assert(sizeof(uuid) <= sizeof(*pReq));
883 memcpy(&uuid, pReq, sizeof(uuid));
884
885 ComObjPtr<HostNetworkInterface> IfObj;
886 IfObj.createObject();
887 if (SUCCEEDED(IfObj->init(Bstr(pReq->ifr_name), Guid(uuid), HostNetworkInterfaceType_Bridged)))
888 list.push_back(IfObj);
889 }
890 }
891 }
892 }
893 close(sock);
894 }
895# endif /* RT_OS_LINUX */
896# endif
897
898 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
899 for (it = list.begin(); it != list.end(); ++it)
900 {
901 (*it)->setVirtualBox(m->pParent);
902 }
903
904 SafeIfaceArray<IHostNetworkInterface> networkInterfaces (list);
905 networkInterfaces.detachTo(ComSafeArrayOutArg(aNetworkInterfaces));
906
907 return S_OK;
908
909#else
910 /* Not implemented / supported on this platform. */
911 ReturnComNotImplemented();
912#endif
913}
914
915STDMETHODIMP Host::COMGETTER(USBDevices)(ComSafeArrayOut(IHostUSBDevice*, aUSBDevices))
916{
917#ifdef VBOX_WITH_USB
918 CheckComArgOutSafeArrayPointerValid(aUSBDevices);
919
920 AutoCaller autoCaller(this);
921 if (FAILED(autoCaller.rc())) return autoCaller.rc();
922
923 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
924
925 MultiResult rc = checkUSBProxyService();
926 if (FAILED(rc)) return rc;
927
928 return m->pUSBProxyService->getDeviceCollection(ComSafeArrayOutArg(aUSBDevices));
929
930#else
931 /* Note: The GUI depends on this method returning E_NOTIMPL with no
932 * extended error info to indicate that USB is simply not available
933 * (w/o treating it as a failure), for example, as in OSE. */
934 NOREF(aUSBDevices);
935# ifndef RT_OS_WINDOWS
936 NOREF(aUSBDevicesSize);
937# endif
938 ReturnComNotImplemented();
939#endif
940}
941
942STDMETHODIMP Host::COMGETTER(USBDeviceFilters)(ComSafeArrayOut(IHostUSBDeviceFilter*, aUSBDeviceFilters))
943{
944#ifdef VBOX_WITH_USB
945 CheckComArgOutSafeArrayPointerValid(aUSBDeviceFilters);
946
947 AutoCaller autoCaller(this);
948 if (FAILED(autoCaller.rc())) return autoCaller.rc();
949
950 AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
951
952 MultiResult rc = checkUSBProxyService();
953 if (FAILED(rc)) return rc;
954
955 SafeIfaceArray<IHostUSBDeviceFilter> collection(m->llUSBDeviceFilters);
956 collection.detachTo(ComSafeArrayOutArg(aUSBDeviceFilters));
957
958 return rc;
959#else
960 /* Note: The GUI depends on this method returning E_NOTIMPL with no
961 * extended error info to indicate that USB is simply not available
962 * (w/o treating it as a failure), for example, as in OSE. */
963 NOREF(aUSBDeviceFilters);
964# ifndef RT_OS_WINDOWS
965 NOREF(aUSBDeviceFiltersSize);
966# endif
967 ReturnComNotImplemented();
968#endif
969}
970
971/**
972 * Returns the number of installed logical processors
973 *
974 * @returns COM status code
975 * @param count address of result variable
976 */
977STDMETHODIMP Host::COMGETTER(ProcessorCount)(ULONG *aCount)
978{
979 CheckComArgOutPointerValid(aCount);
980 // no locking required
981
982 *aCount = RTMpGetPresentCount();
983 return S_OK;
984}
985
986/**
987 * Returns the number of online logical processors
988 *
989 * @returns COM status code
990 * @param count address of result variable
991 */
992STDMETHODIMP Host::COMGETTER(ProcessorOnlineCount)(ULONG *aCount)
993{
994 CheckComArgOutPointerValid(aCount);
995 // no locking required
996
997 *aCount = RTMpGetOnlineCount();
998 return S_OK;
999}
1000
1001/**
1002 * Returns the (approximate) maximum speed of the given host CPU in MHz
1003 *
1004 * @returns COM status code
1005 * @param cpu id to get info for.
1006 * @param speed address of result variable, speed is 0 if unknown or aCpuId is invalid.
1007 */
1008STDMETHODIMP Host::GetProcessorSpeed(ULONG aCpuId, ULONG *aSpeed)
1009{
1010 CheckComArgOutPointerValid(aSpeed);
1011 // no locking required
1012
1013 *aSpeed = RTMpGetMaxFrequency(aCpuId);
1014 return S_OK;
1015}
1016
1017/**
1018 * Returns a description string for the host CPU
1019 *
1020 * @returns COM status code
1021 * @param cpu id to get info for.
1022 * @param description address of result variable, empty string if not known or aCpuId is invalid.
1023 */
1024STDMETHODIMP Host::GetProcessorDescription(ULONG aCpuId, BSTR *aDescription)
1025{
1026 CheckComArgOutPointerValid(aDescription);
1027 // no locking required
1028
1029 char szCPUModel[80];
1030 int vrc = RTMpGetDescription(aCpuId, szCPUModel, sizeof(szCPUModel));
1031 if (RT_FAILURE(vrc))
1032 return E_FAIL; /** @todo error reporting? */
1033 Bstr (szCPUModel).cloneTo(aDescription);
1034 return S_OK;
1035}
1036
1037/**
1038 * Returns whether a host processor feature is supported or not
1039 *
1040 * @returns COM status code
1041 * @param Feature to query.
1042 * @param address of supported bool result variable
1043 */
1044STDMETHODIMP Host::GetProcessorFeature(ProcessorFeature_T aFeature, BOOL *aSupported)
1045{
1046 CheckComArgOutPointerValid(aSupported);
1047 AutoCaller autoCaller(this);
1048 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1049
1050 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1051
1052 switch (aFeature)
1053 {
1054 case ProcessorFeature_HWVirtEx:
1055 *aSupported = m->fVTSupported;
1056 break;
1057
1058 case ProcessorFeature_PAE:
1059 *aSupported = m->fPAESupported;
1060 break;
1061
1062 case ProcessorFeature_LongMode:
1063 *aSupported = m->fLongModeSupported;
1064 break;
1065
1066 case ProcessorFeature_NestedPaging:
1067 *aSupported = m->fNestedPagingSupported;
1068 break;
1069
1070 default:
1071 ReturnComNotImplemented();
1072 }
1073 return S_OK;
1074}
1075
1076/**
1077 * Returns the specific CPUID leaf.
1078 *
1079 * @returns COM status code
1080 * @param aCpuId The CPU number. Mostly ignored.
1081 * @param aLeaf The leaf number.
1082 * @param aSubLeaf The sub-leaf number.
1083 * @param aValEAX Where to return EAX.
1084 * @param aValEBX Where to return EBX.
1085 * @param aValECX Where to return ECX.
1086 * @param aValEDX Where to return EDX.
1087 */
1088STDMETHODIMP Host::GetProcessorCpuIdLeaf(ULONG aCpuId, ULONG aLeaf, ULONG aSubLeaf,
1089 ULONG *aValEAX, ULONG *aValEBX, ULONG *aValECX, ULONG *aValEDX)
1090{
1091 CheckComArgOutPointerValid(aValEAX);
1092 CheckComArgOutPointerValid(aValEBX);
1093 CheckComArgOutPointerValid(aValECX);
1094 CheckComArgOutPointerValid(aValEDX);
1095 // no locking required
1096
1097 /* Check that the CPU is online. */
1098 /** @todo later use RTMpOnSpecific. */
1099 if (!RTMpIsCpuOnline(aCpuId))
1100 return RTMpIsCpuPresent(aCpuId)
1101 ? setError(E_FAIL, tr("CPU no.%u is not present"), aCpuId)
1102 : setError(E_FAIL, tr("CPU no.%u is not online"), aCpuId);
1103
1104 uint32_t uEAX, uEBX, uECX, uEDX;
1105 ASMCpuId_Idx_ECX(aLeaf, aSubLeaf, &uEAX, &uEBX, &uECX, &uEDX);
1106 *aValEAX = uEAX;
1107 *aValEBX = uEBX;
1108 *aValECX = uECX;
1109 *aValEDX = uEDX;
1110
1111 return S_OK;
1112}
1113
1114/**
1115 * Returns the amount of installed system memory in megabytes
1116 *
1117 * @returns COM status code
1118 * @param size address of result variable
1119 */
1120STDMETHODIMP Host::COMGETTER(MemorySize)(ULONG *aSize)
1121{
1122 CheckComArgOutPointerValid(aSize);
1123 // no locking required
1124
1125 /* @todo This is an ugly hack. There must be a function in IPRT for that. */
1126 pm::CollectorHAL *hal = pm::createHAL();
1127 if (!hal)
1128 return E_FAIL;
1129 ULONG tmp;
1130 int rc = hal->getHostMemoryUsage(aSize, &tmp, &tmp);
1131 *aSize /= 1024;
1132 delete hal;
1133 return rc;
1134}
1135
1136/**
1137 * Returns the current system memory free space in megabytes
1138 *
1139 * @returns COM status code
1140 * @param available address of result variable
1141 */
1142STDMETHODIMP Host::COMGETTER(MemoryAvailable)(ULONG *aAvailable)
1143{
1144 CheckComArgOutPointerValid(aAvailable);
1145 // no locking required
1146
1147 /* @todo This is an ugly hack. There must be a function in IPRT for that. */
1148 pm::CollectorHAL *hal = pm::createHAL();
1149 if (!hal)
1150 return E_FAIL;
1151 ULONG tmp;
1152 int rc = hal->getHostMemoryUsage(&tmp, &tmp, aAvailable);
1153 *aAvailable /= 1024;
1154 delete hal;
1155 return rc;
1156}
1157
1158/**
1159 * Returns the name string of the host operating system
1160 *
1161 * @returns COM status code
1162 * @param os address of result variable
1163 */
1164STDMETHODIMP Host::COMGETTER(OperatingSystem)(BSTR *aOs)
1165{
1166 CheckComArgOutPointerValid(aOs);
1167 // no locking required
1168
1169 char szOSName[80];
1170 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szOSName, sizeof(szOSName));
1171 if (RT_FAILURE(vrc))
1172 return E_FAIL; /** @todo error reporting? */
1173 Bstr (szOSName).cloneTo(aOs);
1174 return S_OK;
1175}
1176
1177/**
1178 * Returns the version string of the host operating system
1179 *
1180 * @returns COM status code
1181 * @param os address of result variable
1182 */
1183STDMETHODIMP Host::COMGETTER(OSVersion)(BSTR *aVersion)
1184{
1185 CheckComArgOutPointerValid(aVersion);
1186 // no locking required
1187
1188 /* Get the OS release. Reserve some buffer space for the service pack. */
1189 char szOSRelease[128];
1190 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOSRelease, sizeof(szOSRelease) - 32);
1191 if (RT_FAILURE(vrc))
1192 return E_FAIL; /** @todo error reporting? */
1193
1194 /* Append the service pack if present. */
1195 char szOSServicePack[80];
1196 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szOSServicePack, sizeof(szOSServicePack));
1197 if (RT_FAILURE(vrc))
1198 {
1199 if (vrc != VERR_NOT_SUPPORTED)
1200 return E_FAIL; /** @todo error reporting? */
1201 szOSServicePack[0] = '\0';
1202 }
1203 if (szOSServicePack[0] != '\0')
1204 {
1205 char *psz = strchr(szOSRelease, '\0');
1206 RTStrPrintf(psz, &szOSRelease[sizeof(szOSRelease)] - psz, "sp%s", szOSServicePack);
1207 }
1208
1209 Bstr(szOSRelease).cloneTo(aVersion);
1210 return S_OK;
1211}
1212
1213/**
1214 * Returns the current host time in milliseconds since 1970-01-01 UTC.
1215 *
1216 * @returns COM status code
1217 * @param time address of result variable
1218 */
1219STDMETHODIMP Host::COMGETTER(UTCTime)(LONG64 *aUTCTime)
1220{
1221 CheckComArgOutPointerValid(aUTCTime);
1222 // no locking required
1223
1224 RTTIMESPEC now;
1225 *aUTCTime = RTTimeSpecGetMilli(RTTimeNow(&now));
1226
1227 return S_OK;
1228}
1229
1230STDMETHODIMP Host::COMGETTER(Acceleration3DAvailable)(BOOL *aSupported)
1231{
1232 CheckComArgOutPointerValid(aSupported);
1233 AutoCaller autoCaller(this);
1234 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1235
1236 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1237
1238 *aSupported = m->f3DAccelerationSupported;
1239
1240 return S_OK;
1241}
1242
1243STDMETHODIMP Host::CreateHostOnlyNetworkInterface(IHostNetworkInterface **aHostNetworkInterface,
1244 IProgress **aProgress)
1245{
1246 CheckComArgOutPointerValid(aHostNetworkInterface);
1247 CheckComArgOutPointerValid(aProgress);
1248
1249 AutoCaller autoCaller(this);
1250 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1251
1252 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1253
1254 int r = NetIfCreateHostOnlyNetworkInterface(m->pParent, aHostNetworkInterface, aProgress);
1255 if (RT_SUCCESS(r))
1256 return S_OK;
1257
1258 return r == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
1259}
1260
1261STDMETHODIMP Host::RemoveHostOnlyNetworkInterface(IN_BSTR aId,
1262 IProgress **aProgress)
1263{
1264 CheckComArgOutPointerValid(aProgress);
1265
1266 AutoCaller autoCaller(this);
1267 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1268
1269 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1270
1271 /* first check whether an interface with the given name already exists */
1272 {
1273 ComPtr<IHostNetworkInterface> iface;
1274 if (FAILED(FindHostNetworkInterfaceById(aId,
1275 iface.asOutParam())))
1276 return setError(VBOX_E_OBJECT_NOT_FOUND,
1277 tr("Host network interface with UUID {%RTuuid} does not exist"),
1278 Guid (aId).raw());
1279 }
1280
1281 int r = NetIfRemoveHostOnlyNetworkInterface(m->pParent, Guid(aId), aProgress);
1282 if (RT_SUCCESS(r))
1283 return S_OK;
1284
1285 return r == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
1286}
1287
1288STDMETHODIMP Host::CreateUSBDeviceFilter(IN_BSTR aName,
1289 IHostUSBDeviceFilter **aFilter)
1290{
1291#ifdef VBOX_WITH_USB
1292 CheckComArgStrNotEmptyOrNull(aName);
1293 CheckComArgOutPointerValid(aFilter);
1294
1295 AutoCaller autoCaller(this);
1296 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1297
1298 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1299
1300 ComObjPtr<HostUSBDeviceFilter> filter;
1301 filter.createObject();
1302 HRESULT rc = filter->init (this, aName);
1303 ComAssertComRCRet (rc, rc);
1304 rc = filter.queryInterfaceTo(aFilter);
1305 AssertComRCReturn (rc, rc);
1306 return S_OK;
1307#else
1308 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1309 * extended error info to indicate that USB is simply not available
1310 * (w/o treating it as a failure), for example, as in OSE. */
1311 NOREF(aName);
1312 NOREF(aFilter);
1313 ReturnComNotImplemented();
1314#endif
1315}
1316
1317STDMETHODIMP Host::InsertUSBDeviceFilter(ULONG aPosition,
1318 IHostUSBDeviceFilter *aFilter)
1319{
1320#ifdef VBOX_WITH_USB
1321 CheckComArgNotNull(aFilter);
1322
1323 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1324 AutoCaller autoCaller(this);
1325 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1326
1327 AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1328
1329 MultiResult rc = checkUSBProxyService();
1330 if (FAILED(rc)) return rc;
1331
1332 ComObjPtr<HostUSBDeviceFilter> pFilter;
1333 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
1334 it != m->llChildren.end();
1335 ++it)
1336 {
1337 if (*it == aFilter)
1338 {
1339 pFilter = *it;
1340 break;
1341 }
1342 }
1343 if (pFilter.isNull())
1344 return setError(VBOX_E_INVALID_OBJECT_STATE,
1345 tr("The given USB device filter is not created within this VirtualBox instance"));
1346
1347 if (pFilter->mInList)
1348 return setError (E_INVALIDARG,
1349 tr ("The given USB device filter is already in the list"));
1350
1351 /* iterate to the position... */
1352 USBDeviceFilterList::iterator it = m->llUSBDeviceFilters.begin();
1353 std::advance (it, aPosition);
1354 /* ...and insert */
1355 m->llUSBDeviceFilters.insert(it, pFilter);
1356 pFilter->mInList = true;
1357
1358 /* notify the proxy (only when the filter is active) */
1359 if ( m->pUSBProxyService->isActive()
1360 && pFilter->getData().mActive)
1361 {
1362 ComAssertRet(pFilter->getId() == NULL, E_FAIL);
1363 pFilter->getId() = m->pUSBProxyService->insertFilter(&pFilter->getData().mUSBFilter);
1364 }
1365
1366 /* save the global settings */
1367 alock.release();
1368 return rc = m->pParent->saveSettings();
1369#else
1370 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1371 * extended error info to indicate that USB is simply not available
1372 * (w/o treating it as a failure), for example, as in OSE. */
1373 NOREF(aPosition);
1374 NOREF(aFilter);
1375 ReturnComNotImplemented();
1376#endif
1377}
1378
1379STDMETHODIMP Host::RemoveUSBDeviceFilter(ULONG aPosition)
1380{
1381#ifdef VBOX_WITH_USB
1382
1383 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1384 AutoCaller autoCaller(this);
1385 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1386
1387 AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1388
1389 MultiResult rc = checkUSBProxyService();
1390 if (FAILED(rc)) return rc;
1391
1392 if (!m->llUSBDeviceFilters.size())
1393 return setError (E_INVALIDARG,
1394 tr ("The USB device filter list is empty"));
1395
1396 if (aPosition >= m->llUSBDeviceFilters.size())
1397 return setError (E_INVALIDARG,
1398 tr ("Invalid position: %lu (must be in range [0, %lu])"),
1399 aPosition, m->llUSBDeviceFilters.size() - 1);
1400
1401 ComObjPtr<HostUSBDeviceFilter> filter;
1402 {
1403 /* iterate to the position... */
1404 USBDeviceFilterList::iterator it = m->llUSBDeviceFilters.begin();
1405 std::advance (it, aPosition);
1406 /* ...get an element from there... */
1407 filter = *it;
1408 /* ...and remove */
1409 filter->mInList = false;
1410 m->llUSBDeviceFilters.erase(it);
1411 }
1412
1413 /* notify the proxy (only when the filter is active) */
1414 if (m->pUSBProxyService->isActive() && filter->getData().mActive)
1415 {
1416 ComAssertRet(filter->getId() != NULL, E_FAIL);
1417 m->pUSBProxyService->removeFilter(filter->getId());
1418 filter->getId() = NULL;
1419 }
1420
1421 /* save the global settings */
1422 alock.release();
1423 return rc = m->pParent->saveSettings();
1424#else
1425 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1426 * extended error info to indicate that USB is simply not available
1427 * (w/o treating it as a failure), for example, as in OSE. */
1428 NOREF(aPosition);
1429 ReturnComNotImplemented();
1430#endif
1431}
1432
1433STDMETHODIMP Host::FindHostDVDDrive(IN_BSTR aName, IMedium **aDrive)
1434{
1435 CheckComArgNotNull(aName);
1436 CheckComArgOutPointerValid(aDrive);
1437
1438 *aDrive = NULL;
1439
1440 SafeIfaceArray<IMedium> drivevec;
1441 HRESULT rc = COMGETTER(DVDDrives)(ComSafeArrayAsOutParam(drivevec));
1442 if (FAILED(rc)) return rc;
1443
1444 for (size_t i = 0; i < drivevec.size(); ++i)
1445 {
1446 ComPtr<IMedium> drive = drivevec[i];
1447 Bstr name, location;
1448 rc = drive->COMGETTER(Name)(name.asOutParam());
1449 if (FAILED(rc)) return rc;
1450 rc = drive->COMGETTER(Location)(location.asOutParam());
1451 if (FAILED(rc)) return rc;
1452 if (name == aName || location == aName)
1453 return drive.queryInterfaceTo(aDrive);
1454 }
1455
1456 return setError(VBOX_E_OBJECT_NOT_FOUND,
1457 Medium::tr("The host DVD drive named '%ls' could not be found"), aName);
1458}
1459
1460STDMETHODIMP Host::FindHostFloppyDrive(IN_BSTR aName, IMedium **aDrive)
1461{
1462 CheckComArgNotNull(aName);
1463 CheckComArgOutPointerValid(aDrive);
1464
1465 *aDrive = NULL;
1466
1467 SafeIfaceArray<IMedium> drivevec;
1468 HRESULT rc = COMGETTER(FloppyDrives)(ComSafeArrayAsOutParam(drivevec));
1469 if (FAILED(rc)) return rc;
1470
1471 for (size_t i = 0; i < drivevec.size(); ++i)
1472 {
1473 ComPtr<IMedium> drive = drivevec[i];
1474 Bstr name;
1475 rc = drive->COMGETTER(Name)(name.asOutParam());
1476 if (FAILED(rc)) return rc;
1477 if (name == aName)
1478 return drive.queryInterfaceTo(aDrive);
1479 }
1480
1481 return setError(VBOX_E_OBJECT_NOT_FOUND,
1482 Medium::tr("The host floppy drive named '%ls' could not be found"), aName);
1483}
1484
1485STDMETHODIMP Host::FindHostNetworkInterfaceByName(IN_BSTR name, IHostNetworkInterface **networkInterface)
1486{
1487#ifndef VBOX_WITH_HOSTNETIF_API
1488 return E_NOTIMPL;
1489#else
1490 if (!name)
1491 return E_INVALIDARG;
1492 if (!networkInterface)
1493 return E_POINTER;
1494
1495 *networkInterface = NULL;
1496 ComObjPtr<HostNetworkInterface> found;
1497 std::list <ComObjPtr<HostNetworkInterface> > list;
1498 int rc = NetIfList(list);
1499 if (RT_FAILURE(rc))
1500 {
1501 Log(("Failed to get host network interface list with rc=%Vrc\n", rc));
1502 return E_FAIL;
1503 }
1504 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
1505 for (it = list.begin(); it != list.end(); ++it)
1506 {
1507 Bstr n;
1508 (*it)->COMGETTER(Name) (n.asOutParam());
1509 if (n == name)
1510 found = *it;
1511 }
1512
1513 if (!found)
1514 return setError (E_INVALIDARG, HostNetworkInterface::tr (
1515 "The host network interface with the given name could not be found"));
1516
1517 found->setVirtualBox(m->pParent);
1518
1519 return found.queryInterfaceTo(networkInterface);
1520#endif
1521}
1522
1523STDMETHODIMP Host::FindHostNetworkInterfaceById(IN_BSTR id, IHostNetworkInterface **networkInterface)
1524{
1525#ifndef VBOX_WITH_HOSTNETIF_API
1526 return E_NOTIMPL;
1527#else
1528 if (Guid(id).isEmpty())
1529 return E_INVALIDARG;
1530 if (!networkInterface)
1531 return E_POINTER;
1532
1533 *networkInterface = NULL;
1534 ComObjPtr<HostNetworkInterface> found;
1535 std::list <ComObjPtr<HostNetworkInterface> > list;
1536 int rc = NetIfList(list);
1537 if (RT_FAILURE(rc))
1538 {
1539 Log(("Failed to get host network interface list with rc=%Vrc\n", rc));
1540 return E_FAIL;
1541 }
1542 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
1543 for (it = list.begin(); it != list.end(); ++it)
1544 {
1545 Bstr g;
1546 (*it)->COMGETTER(Id) (g.asOutParam());
1547 if (g == id)
1548 found = *it;
1549 }
1550
1551 if (!found)
1552 return setError (E_INVALIDARG, HostNetworkInterface::tr (
1553 "The host network interface with the given GUID could not be found"));
1554
1555 found->setVirtualBox(m->pParent);
1556
1557 return found.queryInterfaceTo(networkInterface);
1558#endif
1559}
1560
1561STDMETHODIMP Host::FindHostNetworkInterfacesOfType(HostNetworkInterfaceType_T type,
1562 ComSafeArrayOut(IHostNetworkInterface *, aNetworkInterfaces))
1563{
1564 std::list <ComObjPtr<HostNetworkInterface> > allList;
1565 int rc = NetIfList(allList);
1566 if(RT_FAILURE(rc))
1567 return E_FAIL;
1568
1569 std::list <ComObjPtr<HostNetworkInterface> > resultList;
1570
1571 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
1572 for (it = allList.begin(); it != allList.end(); ++it)
1573 {
1574 HostNetworkInterfaceType_T t;
1575 HRESULT hr = (*it)->COMGETTER(InterfaceType)(&t);
1576 if(FAILED(hr))
1577 return hr;
1578
1579 if(t == type)
1580 {
1581 (*it)->setVirtualBox(m->pParent);
1582 resultList.push_back (*it);
1583 }
1584 }
1585
1586 SafeIfaceArray<IHostNetworkInterface> filteredNetworkInterfaces (resultList);
1587 filteredNetworkInterfaces.detachTo(ComSafeArrayOutArg(aNetworkInterfaces));
1588
1589 return S_OK;
1590}
1591
1592STDMETHODIMP Host::FindUSBDeviceByAddress(IN_BSTR aAddress,
1593 IHostUSBDevice **aDevice)
1594{
1595#ifdef VBOX_WITH_USB
1596 CheckComArgNotNull(aAddress);
1597 CheckComArgOutPointerValid(aDevice);
1598
1599 *aDevice = NULL;
1600
1601 SafeIfaceArray<IHostUSBDevice> devsvec;
1602 HRESULT rc = COMGETTER(USBDevices) (ComSafeArrayAsOutParam(devsvec));
1603 if (FAILED(rc)) return rc;
1604
1605 for (size_t i = 0; i < devsvec.size(); ++i)
1606 {
1607 Bstr address;
1608 rc = devsvec[i]->COMGETTER(Address) (address.asOutParam());
1609 if (FAILED(rc)) return rc;
1610 if (address == aAddress)
1611 {
1612 return ComObjPtr<IHostUSBDevice> (devsvec[i]).queryInterfaceTo(aDevice);
1613 }
1614 }
1615
1616 return setErrorNoLog (VBOX_E_OBJECT_NOT_FOUND, tr (
1617 "Could not find a USB device with address '%ls'"),
1618 aAddress);
1619
1620#else /* !VBOX_WITH_USB */
1621 NOREF(aAddress);
1622 NOREF(aDevice);
1623 return E_NOTIMPL;
1624#endif /* !VBOX_WITH_USB */
1625}
1626
1627STDMETHODIMP Host::FindUSBDeviceById(IN_BSTR aId,
1628 IHostUSBDevice **aDevice)
1629{
1630#ifdef VBOX_WITH_USB
1631 CheckComArgExpr(aId, Guid (aId).isEmpty() == false);
1632 CheckComArgOutPointerValid(aDevice);
1633
1634 *aDevice = NULL;
1635
1636 SafeIfaceArray<IHostUSBDevice> devsvec;
1637 HRESULT rc = COMGETTER(USBDevices) (ComSafeArrayAsOutParam(devsvec));
1638 if (FAILED(rc)) return rc;
1639
1640 for (size_t i = 0; i < devsvec.size(); ++i)
1641 {
1642 Bstr id;
1643 rc = devsvec[i]->COMGETTER(Id) (id.asOutParam());
1644 if (FAILED(rc)) return rc;
1645 if (id == aId)
1646 {
1647 return ComObjPtr<IHostUSBDevice> (devsvec[i]).queryInterfaceTo(aDevice);
1648 }
1649 }
1650
1651 return setErrorNoLog (VBOX_E_OBJECT_NOT_FOUND, tr (
1652 "Could not find a USB device with uuid {%RTuuid}"),
1653 Guid (aId).raw());
1654
1655#else /* !VBOX_WITH_USB */
1656 NOREF(aId);
1657 NOREF(aDevice);
1658 return E_NOTIMPL;
1659#endif /* !VBOX_WITH_USB */
1660}
1661
1662// public methods only for internal purposes
1663////////////////////////////////////////////////////////////////////////////////
1664
1665HRESULT Host::loadSettings(const settings::Host &data)
1666{
1667 HRESULT rc = S_OK;
1668#ifdef VBOX_WITH_USB
1669 AutoCaller autoCaller(this);
1670 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1671
1672 AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1673
1674
1675 for (settings::USBDeviceFiltersList::const_iterator it = data.llUSBDeviceFilters.begin();
1676 it != data.llUSBDeviceFilters.end();
1677 ++it)
1678 {
1679 const settings::USBDeviceFilter &f = *it;
1680 ComObjPtr<HostUSBDeviceFilter> pFilter;
1681 pFilter.createObject();
1682 rc = pFilter->init(this, f);
1683 if (FAILED(rc)) break;
1684
1685 m->llUSBDeviceFilters.push_back(pFilter);
1686 pFilter->mInList = true;
1687
1688 /* notify the proxy (only when the filter is active) */
1689 if (pFilter->getData().mActive)
1690 {
1691 HostUSBDeviceFilter *flt = pFilter; /* resolve ambiguity */
1692 flt->getId() = m->pUSBProxyService->insertFilter(&pFilter->getData().mUSBFilter);
1693 }
1694 }
1695#else
1696 NOREF(data);
1697#endif /* VBOX_WITH_USB */
1698 return rc;
1699}
1700
1701HRESULT Host::saveSettings(settings::Host &data)
1702{
1703#ifdef VBOX_WITH_USB
1704 AutoCaller autoCaller(this);
1705 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1706
1707 AutoReadLock alock(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1708
1709 data.llUSBDeviceFilters.clear();
1710
1711 for (USBDeviceFilterList::const_iterator it = m->llUSBDeviceFilters.begin();
1712 it != m->llUSBDeviceFilters.end();
1713 ++it)
1714 {
1715 ComObjPtr<HostUSBDeviceFilter> pFilter = *it;
1716 settings::USBDeviceFilter f;
1717 pFilter->saveSettings(f);
1718 data.llUSBDeviceFilters.push_back(f);
1719 }
1720#else
1721 NOREF(data);
1722#endif /* VBOX_WITH_USB */
1723
1724 return S_OK;
1725}
1726
1727#ifdef VBOX_WITH_USB
1728USBProxyService* Host::usbProxyService()
1729{
1730 return m->pUSBProxyService;
1731}
1732
1733HRESULT Host::addChild(HostUSBDeviceFilter *pChild)
1734{
1735 AutoCaller autoCaller(this);
1736 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1737
1738 AutoWriteLock alock(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1739
1740 m->llChildren.push_back(pChild);
1741
1742 return S_OK;
1743}
1744
1745HRESULT Host::removeChild(HostUSBDeviceFilter *pChild)
1746{
1747 AutoCaller autoCaller(this);
1748 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1749
1750 AutoWriteLock alock(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1751
1752 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
1753 it != m->llChildren.end();
1754 ++it)
1755 {
1756 if (*it == pChild)
1757 {
1758 m->llChildren.erase(it);
1759 break;
1760 }
1761 }
1762
1763 return S_OK;
1764}
1765
1766VirtualBox* Host::parent()
1767{
1768 return m->pParent;
1769}
1770
1771/**
1772 * Called by setter methods of all USB device filters.
1773 */
1774HRESULT Host::onUSBDeviceFilterChange(HostUSBDeviceFilter *aFilter,
1775 BOOL aActiveChanged /* = FALSE */)
1776{
1777 AutoCaller autoCaller(this);
1778 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1779
1780 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1781
1782 if (aFilter->mInList)
1783 {
1784 if (aActiveChanged)
1785 {
1786 // insert/remove the filter from the proxy
1787 if (aFilter->getData().mActive)
1788 {
1789 ComAssertRet(aFilter->getId() == NULL, E_FAIL);
1790 aFilter->getId() = m->pUSBProxyService->insertFilter(&aFilter->getData().mUSBFilter);
1791 }
1792 else
1793 {
1794 ComAssertRet(aFilter->getId() != NULL, E_FAIL);
1795 m->pUSBProxyService->removeFilter(aFilter->getId());
1796 aFilter->getId() = NULL;
1797 }
1798 }
1799 else
1800 {
1801 if (aFilter->getData().mActive)
1802 {
1803 // update the filter in the proxy
1804 ComAssertRet(aFilter->getId() != NULL, E_FAIL);
1805 m->pUSBProxyService->removeFilter(aFilter->getId());
1806 aFilter->getId() = m->pUSBProxyService->insertFilter(&aFilter->getData().mUSBFilter);
1807 }
1808 }
1809
1810 // save the global settings... yeah, on every single filter property change
1811 alock.release();
1812 return m->pParent->saveSettings();
1813 }
1814
1815 return S_OK;
1816}
1817
1818
1819/**
1820 * Interface for obtaining a copy of the USBDeviceFilterList,
1821 * used by the USBProxyService.
1822 *
1823 * @param aGlobalFilters Where to put the global filter list copy.
1824 * @param aMachines Where to put the machine vector.
1825 */
1826void Host::getUSBFilters(Host::USBDeviceFilterList *aGlobalFilters)
1827{
1828 AutoReadLock alock(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1829
1830 *aGlobalFilters = m->llUSBDeviceFilters;
1831}
1832
1833#endif /* VBOX_WITH_USB */
1834
1835// private methods
1836////////////////////////////////////////////////////////////////////////////////
1837
1838#if defined(RT_OS_SOLARIS) && defined(VBOX_USE_LIBHAL)
1839/* Solaris hosts, loading libhal at runtime */
1840
1841/**
1842 * Helper function to query the hal subsystem for information about DVD drives attached to the
1843 * system.
1844 *
1845 * @returns true if information was successfully obtained, false otherwise
1846 * @retval list drives found will be attached to this list
1847 */
1848bool Host::getDVDInfoFromHal(std::list<ComObjPtr<Medium> > &list)
1849{
1850 bool halSuccess = false;
1851 DBusError dbusError;
1852 if (!gLibHalCheckPresence())
1853 return false;
1854 gDBusErrorInit (&dbusError);
1855 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
1856 if (dbusConnection != 0)
1857 {
1858 LibHalContext *halContext = gLibHalCtxNew();
1859 if (halContext != 0)
1860 {
1861 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
1862 {
1863 if (gLibHalCtxInit(halContext, &dbusError))
1864 {
1865 int numDevices;
1866 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
1867 "storage.drive_type", "cdrom",
1868 &numDevices, &dbusError);
1869 if (halDevices != 0)
1870 {
1871 /* Hal is installed and working, so if no devices are reported, assume
1872 that there are none. */
1873 halSuccess = true;
1874 for (int i = 0; i < numDevices; i++)
1875 {
1876 char *devNode = gLibHalDeviceGetPropertyString(halContext,
1877 halDevices[i], "block.device", &dbusError);
1878#ifdef RT_OS_SOLARIS
1879 /* The CD/DVD ioctls work only for raw device nodes. */
1880 char *tmp = getfullrawname(devNode);
1881 gLibHalFreeString(devNode);
1882 devNode = tmp;
1883#endif
1884
1885 if (devNode != 0)
1886 {
1887// if (validateDevice(devNode, true))
1888// {
1889 Utf8Str description;
1890 char *vendor, *product;
1891 /* We do not check the error here, as this field may
1892 not even exist. */
1893 vendor = gLibHalDeviceGetPropertyString(halContext,
1894 halDevices[i], "info.vendor", 0);
1895 product = gLibHalDeviceGetPropertyString(halContext,
1896 halDevices[i], "info.product", &dbusError);
1897 if ((product != 0 && product[0] != 0))
1898 {
1899 if ((vendor != 0) && (vendor[0] != 0))
1900 {
1901 description = Utf8StrFmt ("%s %s",
1902 vendor, product);
1903 }
1904 else
1905 {
1906 description = product;
1907 }
1908 ComObjPtr<Medium> hostDVDDriveObj;
1909 hostDVDDriveObj.createObject();
1910 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
1911 Bstr(devNode), Bstr(description));
1912 list.push_back (hostDVDDriveObj);
1913 }
1914 else
1915 {
1916 if (product == 0)
1917 {
1918 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
1919 halDevices[i], dbusError.name, dbusError.message));
1920 gDBusErrorFree(&dbusError);
1921 }
1922 ComObjPtr<Medium> hostDVDDriveObj;
1923 hostDVDDriveObj.createObject();
1924 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
1925 Bstr(devNode));
1926 list.push_back (hostDVDDriveObj);
1927 }
1928 if (vendor != 0)
1929 {
1930 gLibHalFreeString(vendor);
1931 }
1932 if (product != 0)
1933 {
1934 gLibHalFreeString(product);
1935 }
1936// }
1937// else
1938// {
1939// LogRel(("Host::COMGETTER(DVDDrives): failed to validate the block device %s as a DVD drive\n"));
1940// }
1941#ifndef RT_OS_SOLARIS
1942 gLibHalFreeString(devNode);
1943#else
1944 free(devNode);
1945#endif
1946 }
1947 else
1948 {
1949 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
1950 halDevices[i], dbusError.name, dbusError.message));
1951 gDBusErrorFree(&dbusError);
1952 }
1953 }
1954 gLibHalFreeStringArray(halDevices);
1955 }
1956 else
1957 {
1958 LogRel(("Host::COMGETTER(DVDDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1959 gDBusErrorFree(&dbusError);
1960 }
1961 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
1962 {
1963 LogRel(("Host::COMGETTER(DVDDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1964 gDBusErrorFree(&dbusError);
1965 }
1966 }
1967 else
1968 {
1969 LogRel(("Host::COMGETTER(DVDDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1970 gDBusErrorFree(&dbusError);
1971 }
1972 gLibHalCtxFree(halContext);
1973 }
1974 else
1975 {
1976 LogRel(("Host::COMGETTER(DVDDrives): failed to set libhal connection to dbus.\n"));
1977 }
1978 }
1979 else
1980 {
1981 LogRel(("Host::COMGETTER(DVDDrives): failed to get a libhal context - out of memory?\n"));
1982 }
1983 gDBusConnectionUnref(dbusConnection);
1984 }
1985 else
1986 {
1987 LogRel(("Host::COMGETTER(DVDDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1988 gDBusErrorFree(&dbusError);
1989 }
1990 return halSuccess;
1991}
1992
1993
1994/**
1995 * Helper function to query the hal subsystem for information about floppy drives attached to the
1996 * system.
1997 *
1998 * @returns true if information was successfully obtained, false otherwise
1999 * @retval list drives found will be attached to this list
2000 */
2001bool Host::getFloppyInfoFromHal(std::list< ComObjPtr<Medium> > &list)
2002{
2003 bool halSuccess = false;
2004 DBusError dbusError;
2005 if (!gLibHalCheckPresence())
2006 return false;
2007 gDBusErrorInit (&dbusError);
2008 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
2009 if (dbusConnection != 0)
2010 {
2011 LibHalContext *halContext = gLibHalCtxNew();
2012 if (halContext != 0)
2013 {
2014 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
2015 {
2016 if (gLibHalCtxInit(halContext, &dbusError))
2017 {
2018 int numDevices;
2019 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
2020 "storage.drive_type", "floppy",
2021 &numDevices, &dbusError);
2022 if (halDevices != 0)
2023 {
2024 /* Hal is installed and working, so if no devices are reported, assume
2025 that there are none. */
2026 halSuccess = true;
2027 for (int i = 0; i < numDevices; i++)
2028 {
2029 char *driveType = gLibHalDeviceGetPropertyString(halContext,
2030 halDevices[i], "storage.drive_type", 0);
2031 if (driveType != 0)
2032 {
2033 if (strcmp(driveType, "floppy") != 0)
2034 {
2035 gLibHalFreeString(driveType);
2036 continue;
2037 }
2038 gLibHalFreeString(driveType);
2039 }
2040 else
2041 {
2042 /* An error occurred. The attribute "storage.drive_type"
2043 probably didn't exist. */
2044 continue;
2045 }
2046 char *devNode = gLibHalDeviceGetPropertyString(halContext,
2047 halDevices[i], "block.device", &dbusError);
2048 if (devNode != 0)
2049 {
2050// if (validateDevice(devNode, false))
2051// {
2052 Utf8Str description;
2053 char *vendor, *product;
2054 /* We do not check the error here, as this field may
2055 not even exist. */
2056 vendor = gLibHalDeviceGetPropertyString(halContext,
2057 halDevices[i], "info.vendor", 0);
2058 product = gLibHalDeviceGetPropertyString(halContext,
2059 halDevices[i], "info.product", &dbusError);
2060 if ((product != 0) && (product[0] != 0))
2061 {
2062 if ((vendor != 0) && (vendor[0] != 0))
2063 {
2064 description = Utf8StrFmt ("%s %s",
2065 vendor, product);
2066 }
2067 else
2068 {
2069 description = product;
2070 }
2071 ComObjPtr<Medium> hostFloppyDrive;
2072 hostFloppyDrive.createObject();
2073 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
2074 Bstr(devNode), Bstr(description));
2075 list.push_back (hostFloppyDrive);
2076 }
2077 else
2078 {
2079 if (product == 0)
2080 {
2081 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
2082 halDevices[i], dbusError.name, dbusError.message));
2083 gDBusErrorFree(&dbusError);
2084 }
2085 ComObjPtr<Medium> hostFloppyDrive;
2086 hostFloppyDrive.createObject();
2087 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
2088 Bstr(devNode));
2089 list.push_back (hostFloppyDrive);
2090 }
2091 if (vendor != 0)
2092 {
2093 gLibHalFreeString(vendor);
2094 }
2095 if (product != 0)
2096 {
2097 gLibHalFreeString(product);
2098 }
2099// }
2100// else
2101// {
2102// LogRel(("Host::COMGETTER(FloppyDrives): failed to validate the block device %s as a floppy drive\n"));
2103// }
2104 gLibHalFreeString(devNode);
2105 }
2106 else
2107 {
2108 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
2109 halDevices[i], dbusError.name, dbusError.message));
2110 gDBusErrorFree(&dbusError);
2111 }
2112 }
2113 gLibHalFreeStringArray(halDevices);
2114 }
2115 else
2116 {
2117 LogRel(("Host::COMGETTER(FloppyDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2118 gDBusErrorFree(&dbusError);
2119 }
2120 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
2121 {
2122 LogRel(("Host::COMGETTER(FloppyDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2123 gDBusErrorFree(&dbusError);
2124 }
2125 }
2126 else
2127 {
2128 LogRel(("Host::COMGETTER(FloppyDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2129 gDBusErrorFree(&dbusError);
2130 }
2131 gLibHalCtxFree(halContext);
2132 }
2133 else
2134 {
2135 LogRel(("Host::COMGETTER(FloppyDrives): failed to set libhal connection to dbus.\n"));
2136 }
2137 }
2138 else
2139 {
2140 LogRel(("Host::COMGETTER(FloppyDrives): failed to get a libhal context - out of memory?\n"));
2141 }
2142 gDBusConnectionUnref(dbusConnection);
2143 }
2144 else
2145 {
2146 LogRel(("Host::COMGETTER(FloppyDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2147 gDBusErrorFree(&dbusError);
2148 }
2149 return halSuccess;
2150}
2151#endif /* RT_OS_SOLARIS and VBOX_USE_HAL */
2152
2153/** @todo get rid of dead code below - RT_OS_SOLARIS and RT_OS_LINUX are never both set */
2154#if defined(RT_OS_SOLARIS)
2155
2156/**
2157 * Helper function to parse the given mount file and add found entries
2158 */
2159void Host::parseMountTable(char *mountTable, std::list< ComObjPtr<Medium> > &list)
2160{
2161#ifdef RT_OS_LINUX
2162 FILE *mtab = setmntent(mountTable, "r");
2163 if (mtab)
2164 {
2165 struct mntent *mntent;
2166 char *mnt_type;
2167 char *mnt_dev;
2168 char *tmp;
2169 while ((mntent = getmntent(mtab)))
2170 {
2171 mnt_type = (char*)malloc(strlen(mntent->mnt_type) + 1);
2172 mnt_dev = (char*)malloc(strlen(mntent->mnt_fsname) + 1);
2173 strcpy(mnt_type, mntent->mnt_type);
2174 strcpy(mnt_dev, mntent->mnt_fsname);
2175 // supermount fs case
2176 if (strcmp(mnt_type, "supermount") == 0)
2177 {
2178 tmp = strstr(mntent->mnt_opts, "fs=");
2179 if (tmp)
2180 {
2181 free(mnt_type);
2182 mnt_type = strdup(tmp + strlen("fs="));
2183 if (mnt_type)
2184 {
2185 tmp = strchr(mnt_type, ',');
2186 if (tmp)
2187 *tmp = '\0';
2188 }
2189 }
2190 tmp = strstr(mntent->mnt_opts, "dev=");
2191 if (tmp)
2192 {
2193 free(mnt_dev);
2194 mnt_dev = strdup(tmp + strlen("dev="));
2195 if (mnt_dev)
2196 {
2197 tmp = strchr(mnt_dev, ',');
2198 if (tmp)
2199 *tmp = '\0';
2200 }
2201 }
2202 }
2203 // use strstr here to cover things fs types like "udf,iso9660"
2204 if (strstr(mnt_type, "iso9660") == 0)
2205 {
2206 /** @todo check whether we've already got the drive in our list! */
2207 if (validateDevice(mnt_dev, true))
2208 {
2209 ComObjPtr<Medium> hostDVDDriveObj;
2210 hostDVDDriveObj.createObject();
2211 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(mnt_dev));
2212 list.push_back (hostDVDDriveObj);
2213 }
2214 }
2215 free(mnt_dev);
2216 free(mnt_type);
2217 }
2218 endmntent(mtab);
2219 }
2220#else // RT_OS_SOLARIS
2221 FILE *mntFile = fopen(mountTable, "r");
2222 if (mntFile)
2223 {
2224 struct mnttab mntTab;
2225 while (getmntent(mntFile, &mntTab) == 0)
2226 {
2227 const char *mountName = mntTab.mnt_special;
2228 const char *mountPoint = mntTab.mnt_mountp;
2229 const char *mountFSType = mntTab.mnt_fstype;
2230 if (mountName && mountPoint && mountFSType)
2231 {
2232 // skip devices we are not interested in
2233 if ((*mountName && mountName[0] == '/') && // skip 'fake' devices (like -hosts, proc, fd, swap)
2234 (*mountFSType && (strncmp(mountFSType, "devfs", 5) != 0 && // skip devfs (i.e. /devices)
2235 strncmp(mountFSType, "dev", 3) != 0 && // skip dev (i.e. /dev)
2236 strncmp(mountFSType, "lofs", 4) != 0))) // skip loop-back file-system (lofs)
2237 {
2238 char *rawDevName = getfullrawname((char *)mountName);
2239 if (validateDevice(rawDevName, true))
2240 {
2241 ComObjPtr<Medium> hostDVDDriveObj;
2242 hostDVDDriveObj.createObject();
2243 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(rawDevName));
2244 list.push_back (hostDVDDriveObj);
2245 }
2246 free(rawDevName);
2247 }
2248 }
2249 }
2250
2251 fclose(mntFile);
2252 }
2253#endif
2254}
2255
2256/**
2257 * Helper function to check whether the given device node is a valid drive
2258 */
2259bool Host::validateDevice(const char *deviceNode, bool isCDROM)
2260{
2261 struct stat statInfo;
2262 bool retValue = false;
2263
2264 // sanity check
2265 if (!deviceNode)
2266 {
2267 return false;
2268 }
2269
2270 // first a simple stat() call
2271 if (stat(deviceNode, &statInfo) < 0)
2272 {
2273 return false;
2274 }
2275 else
2276 {
2277 if (isCDROM)
2278 {
2279 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2280 {
2281 int fileHandle;
2282 // now try to open the device
2283 fileHandle = open(deviceNode, O_RDONLY | O_NONBLOCK, 0);
2284 if (fileHandle >= 0)
2285 {
2286 cdrom_subchnl cdChannelInfo;
2287 cdChannelInfo.cdsc_format = CDROM_MSF;
2288 // this call will finally reveal the whole truth
2289#ifdef RT_OS_LINUX
2290 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2291 (errno == EIO) || (errno == ENOENT) ||
2292 (errno == EINVAL) || (errno == ENOMEDIUM))
2293#else
2294 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2295 (errno == EIO) || (errno == ENOENT) ||
2296 (errno == EINVAL))
2297#endif
2298 {
2299 retValue = true;
2300 }
2301 close(fileHandle);
2302 }
2303 }
2304 } else
2305 {
2306 // floppy case
2307 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2308 {
2309 /// @todo do some more testing, maybe a nice IOCTL!
2310 retValue = true;
2311 }
2312 }
2313 }
2314 return retValue;
2315}
2316#endif // RT_OS_SOLARIS
2317
2318#ifdef VBOX_WITH_USB
2319/**
2320 * Checks for the presense and status of the USB Proxy Service.
2321 * Returns S_OK when the Proxy is present and OK, VBOX_E_HOST_ERROR (as a
2322 * warning) if the proxy service is not available due to the way the host is
2323 * configured (at present, that means that usbfs and hal/DBus are not
2324 * available on a Linux host) or E_FAIL and a corresponding error message
2325 * otherwise. Intended to be used by methods that rely on the Proxy Service
2326 * availability.
2327 *
2328 * @note This method may return a warning result code. It is recommended to use
2329 * MultiError to store the return value.
2330 *
2331 * @note Locks this object for reading.
2332 */
2333HRESULT Host::checkUSBProxyService()
2334{
2335 AutoCaller autoCaller(this);
2336 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2337
2338 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2339
2340 AssertReturn(m->pUSBProxyService, E_FAIL);
2341 if (!m->pUSBProxyService->isActive())
2342 {
2343 /* disable the USB controller completely to avoid assertions if the
2344 * USB proxy service could not start. */
2345
2346 if (m->pUSBProxyService->getLastError() == VERR_FILE_NOT_FOUND)
2347 return setWarning (E_FAIL,
2348 tr ("Could not load the Host USB Proxy Service (%Rrc). "
2349 "The service might not be installed on the host computer"),
2350 m->pUSBProxyService->getLastError());
2351 if (m->pUSBProxyService->getLastError() == VINF_SUCCESS)
2352#ifdef RT_OS_LINUX
2353 return setWarning (VBOX_E_HOST_ERROR,
2354# ifdef VBOX_WITH_DBUS
2355 tr ("The USB Proxy Service could not be started, because neither the USB file system (usbfs) nor the hardware information service (hal) is available")
2356# else
2357 tr ("The USB Proxy Service could not be started, because the USB file system (usbfs) is not available")
2358# endif
2359 );
2360#else /* !RT_OS_LINUX */
2361 return setWarning (E_FAIL,
2362 tr ("The USB Proxy Service has not yet been ported to this host"));
2363#endif /* !RT_OS_LINUX */
2364 return setWarning (E_FAIL,
2365 tr ("Could not load the Host USB Proxy service (%Rrc)"),
2366 m->pUSBProxyService->getLastError());
2367 }
2368
2369 return S_OK;
2370}
2371#endif /* VBOX_WITH_USB */
2372
2373#ifdef VBOX_WITH_RESOURCE_USAGE_API
2374void Host::registerMetrics (PerformanceCollector *aCollector)
2375{
2376 pm::CollectorHAL *hal = aCollector->getHAL();
2377 /* Create sub metrics */
2378 pm::SubMetric *cpuLoadUser = new pm::SubMetric ("CPU/Load/User",
2379 "Percentage of processor time spent in user mode.");
2380 pm::SubMetric *cpuLoadKernel = new pm::SubMetric ("CPU/Load/Kernel",
2381 "Percentage of processor time spent in kernel mode.");
2382 pm::SubMetric *cpuLoadIdle = new pm::SubMetric ("CPU/Load/Idle",
2383 "Percentage of processor time spent idling.");
2384 pm::SubMetric *cpuMhzSM = new pm::SubMetric ("CPU/MHz",
2385 "Average of current frequency of all processors.");
2386 pm::SubMetric *ramUsageTotal = new pm::SubMetric ("RAM/Usage/Total",
2387 "Total physical memory installed.");
2388 pm::SubMetric *ramUsageUsed = new pm::SubMetric ("RAM/Usage/Used",
2389 "Physical memory currently occupied.");
2390 pm::SubMetric *ramUsageFree = new pm::SubMetric ("RAM/Usage/Free",
2391 "Physical memory currently available to applications.");
2392 /* Create and register base metrics */
2393 IUnknown *objptr;
2394 ComObjPtr<Host> tmp = this;
2395 tmp.queryInterfaceTo(&objptr);
2396 pm::BaseMetric *cpuLoad = new pm::HostCpuLoadRaw (hal, objptr, cpuLoadUser, cpuLoadKernel,
2397 cpuLoadIdle);
2398 aCollector->registerBaseMetric (cpuLoad);
2399 pm::BaseMetric *cpuMhz = new pm::HostCpuMhz (hal, objptr, cpuMhzSM);
2400 aCollector->registerBaseMetric (cpuMhz);
2401 pm::BaseMetric *ramUsage = new pm::HostRamUsage (hal, objptr, ramUsageTotal, ramUsageUsed,
2402 ramUsageFree);
2403 aCollector->registerBaseMetric (ramUsage);
2404
2405 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadUser, 0));
2406 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadUser,
2407 new pm::AggregateAvg()));
2408 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadUser,
2409 new pm::AggregateMin()));
2410 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadUser,
2411 new pm::AggregateMax()));
2412
2413 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadKernel, 0));
2414 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadKernel,
2415 new pm::AggregateAvg()));
2416 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadKernel,
2417 new pm::AggregateMin()));
2418 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadKernel,
2419 new pm::AggregateMax()));
2420
2421 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadIdle, 0));
2422 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadIdle,
2423 new pm::AggregateAvg()));
2424 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadIdle,
2425 new pm::AggregateMin()));
2426 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadIdle,
2427 new pm::AggregateMax()));
2428
2429 aCollector->registerMetric (new pm::Metric(cpuMhz, cpuMhzSM, 0));
2430 aCollector->registerMetric (new pm::Metric(cpuMhz, cpuMhzSM,
2431 new pm::AggregateAvg()));
2432 aCollector->registerMetric (new pm::Metric(cpuMhz, cpuMhzSM,
2433 new pm::AggregateMin()));
2434 aCollector->registerMetric (new pm::Metric(cpuMhz, cpuMhzSM,
2435 new pm::AggregateMax()));
2436
2437 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageTotal, 0));
2438 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageTotal,
2439 new pm::AggregateAvg()));
2440 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageTotal,
2441 new pm::AggregateMin()));
2442 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageTotal,
2443 new pm::AggregateMax()));
2444
2445 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageUsed, 0));
2446 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageUsed,
2447 new pm::AggregateAvg()));
2448 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageUsed,
2449 new pm::AggregateMin()));
2450 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageUsed,
2451 new pm::AggregateMax()));
2452
2453 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageFree, 0));
2454 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageFree,
2455 new pm::AggregateAvg()));
2456 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageFree,
2457 new pm::AggregateMin()));
2458 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageFree,
2459 new pm::AggregateMax()));
2460};
2461
2462void Host::unregisterMetrics (PerformanceCollector *aCollector)
2463{
2464 aCollector->unregisterMetricsFor (this);
2465 aCollector->unregisterBaseMetricsFor (this);
2466};
2467#endif /* VBOX_WITH_RESOURCE_USAGE_API */
2468
2469/* 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