VirtualBox

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

Last change on this file since 25198 was 25151, checked in by vboxsync, 15 years ago

Main: cleanup: std::list< ComOBjPtr<Medium> > typedefs

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

© 2023 Oracle
ContactPrivacy policyTerms of Use