VirtualBox

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

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

FreeBSD: Bye bye HAL. We use the CAM layer directly to discover CD/DVD devices now

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette