VirtualBox

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

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

Main: sketched 3D hardware support test in IHost

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