VirtualBox

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

Last change on this file since 20131 was 20098, checked in by vboxsync, 16 years ago

Main: report 3d unsupported if sharedopengl isn't build

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