VirtualBox

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

Last change on this file since 25809 was 25809, checked in by vboxsync, 14 years ago

Main: adjust lock validation code to use IPRT lock validation, first steps (not active yet)

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

© 2023 Oracle
ContactPrivacy policyTerms of Use