VirtualBox

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

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

Main: make HostHardwareLinux use MiniString instead of std::string; add exception handling to HostImpl bits

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 87.6 KB
Line 
1/* $Id: HostImpl.cpp 21436 2009-07-09 12:24:28Z 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 bool is3DAccelerationSupported();
115#endif /* VBOX_WITH_CROGL */
116
117#include <iprt/asm.h>
118#include <iprt/string.h>
119#include <iprt/mp.h>
120#include <iprt/time.h>
121#include <iprt/param.h>
122#include <iprt/env.h>
123#include <iprt/mem.h>
124#include <iprt/system.h>
125#ifdef RT_OS_SOLARIS
126# include <iprt/path.h>
127# include <iprt/ctype.h>
128#endif
129#ifdef VBOX_WITH_HOSTNETIF_API
130#include "netif.h"
131#endif
132
133#include <VBox/usb.h>
134#include <VBox/x86.h>
135#include <VBox/err.h>
136#include <VBox/settings.h>
137
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 /* Test for 3D hardware acceleration support */
256 f3DAccelerationSupported = false;
257
258#ifdef VBOX_WITH_CROGL
259 f3DAccelerationSupported = is3DAccelerationSupported();
260#endif /* VBOX_WITH_CROGL */
261
262 setReady(true);
263 return S_OK;
264}
265
266/**
267 * Uninitializes the host object and sets the ready flag to FALSE.
268 * Called either from FinalRelease() or by the parent when it gets destroyed.
269 */
270void Host::uninit()
271{
272 LogFlowThisFunc (("isReady=%d\n", isReady()));
273
274 AssertReturn (isReady(), (void) 0);
275
276#ifdef VBOX_WITH_RESOURCE_USAGE_API
277 unregisterMetrics (mParent->performanceCollector());
278#endif /* VBOX_WITH_RESOURCE_USAGE_API */
279
280#ifdef VBOX_WITH_USB
281 /* wait for USB proxy service to terminate before we uninit all USB
282 * devices */
283 LogFlowThisFunc (("Stopping USB proxy service...\n"));
284 delete mUSBProxyService;
285 mUSBProxyService = NULL;
286 LogFlowThisFunc (("Done stopping USB proxy service.\n"));
287#endif
288
289 delete mHostPowerService;
290
291 /* uninit all USB device filters still referenced by clients */
292 uninitDependentChildren();
293
294#ifdef VBOX_WITH_USB
295 mUSBDeviceFilters.clear();
296#endif
297
298 setReady (FALSE);
299}
300
301// IHost properties
302/////////////////////////////////////////////////////////////////////////////
303
304/**
305 * Returns a list of host DVD drives.
306 *
307 * @returns COM status code
308 * @param drives address of result pointer
309 */
310STDMETHODIMP Host::COMGETTER(DVDDrives) (ComSafeArrayOut (IHostDVDDrive *, aDrives))
311{
312 CheckComArgOutSafeArrayPointerValid(aDrives);
313 AutoWriteLock alock (this);
314 CHECK_READY();
315 std::list <ComObjPtr <HostDVDDrive> > list;
316 HRESULT rc = S_OK;
317 try
318 {
319#if defined(RT_OS_WINDOWS)
320 int sz = GetLogicalDriveStrings(0, NULL);
321 TCHAR *hostDrives = new TCHAR[sz+1];
322 GetLogicalDriveStrings(sz, hostDrives);
323 wchar_t driveName[3] = { '?', ':', '\0' };
324 TCHAR *p = hostDrives;
325 do
326 {
327 if (GetDriveType(p) == DRIVE_CDROM)
328 {
329 driveName[0] = *p;
330 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
331 hostDVDDriveObj.createObject();
332 hostDVDDriveObj->init (Bstr (driveName));
333 list.push_back (hostDVDDriveObj);
334 }
335 p += _tcslen(p) + 1;
336 }
337 while (*p);
338 delete[] hostDrives;
339
340#elif defined(RT_OS_SOLARIS)
341# ifdef VBOX_USE_LIBHAL
342 if (!getDVDInfoFromHal(list))
343# endif
344 // Not all Solaris versions ship with libhal.
345 // So use a fallback approach similar to Linux.
346 {
347 if (RTEnvGet("VBOX_CDROM"))
348 {
349 char *cdromEnv = strdup(RTEnvGet("VBOX_CDROM"));
350 char *cdromDrive;
351 cdromDrive = strtok(cdromEnv, ":"); /** @todo use strtok_r. */
352 while (cdromDrive)
353 {
354 if (validateDevice(cdromDrive, true))
355 {
356 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
357 hostDVDDriveObj.createObject();
358 hostDVDDriveObj->init (Bstr (cdromDrive));
359 list.push_back (hostDVDDriveObj);
360 }
361 cdromDrive = strtok(NULL, ":");
362 }
363 free(cdromEnv);
364 }
365 else
366 {
367 // this might work on Solaris version older than Nevada.
368 if (validateDevice("/cdrom/cdrom0", true))
369 {
370 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
371 hostDVDDriveObj.createObject();
372 hostDVDDriveObj->init (Bstr ("cdrom/cdrom0"));
373 list.push_back (hostDVDDriveObj);
374 }
375
376 // check the mounted drives
377 parseMountTable(MNTTAB, list);
378 }
379 }
380
381#elif defined(RT_OS_LINUX)
382 if (RT_SUCCESS (mHostDrives.updateDVDs()))
383 for (DriveInfoList::const_iterator it = mHostDrives.DVDBegin();
384 SUCCEEDED (rc) && it != mHostDrives.DVDEnd(); ++it)
385 {
386 ComObjPtr<HostDVDDrive> hostDVDDriveObj;
387 Bstr device(it->mDevice);
388 Bstr udi(it->mUdi);
389 Bstr description(it->mDescription);
390 if (SUCCEEDED (rc))
391 rc = hostDVDDriveObj.createObject();
392 if (SUCCEEDED (rc))
393 rc = hostDVDDriveObj->init (device, udi, description);
394 if (SUCCEEDED (rc))
395 list.push_back(hostDVDDriveObj);
396 }
397#elif defined(RT_OS_DARWIN)
398 PDARWINDVD cur = DarwinGetDVDDrives();
399 while (cur)
400 {
401 ComObjPtr<HostDVDDrive> hostDVDDriveObj;
402 hostDVDDriveObj.createObject();
403 hostDVDDriveObj->init(Bstr(cur->szName));
404 list.push_back(hostDVDDriveObj);
405
406 /* next */
407 void *freeMe = cur;
408 cur = cur->pNext;
409 RTMemFree(freeMe);
410 }
411#elif defined(RT_OS_FREEBSD)
412# ifdef VBOX_USE_LIBHAL
413 if (!getDVDInfoFromHal(list))
414# endif
415 {
416 /** @todo: Scan for accessible /dev/cd* devices. */
417 }
418#else
419 /* PORTME */
420#endif
421
422 SafeIfaceArray <IHostDVDDrive> array (list);
423 array.detachTo(ComSafeArrayOutArg(aDrives));
424 }
425 catch(std::bad_alloc &e)
426 {
427 rc = E_OUTOFMEMORY;
428 }
429 return rc;
430}
431
432/**
433 * Returns a list of host floppy drives.
434 *
435 * @returns COM status code
436 * @param drives address of result pointer
437 */
438STDMETHODIMP Host::COMGETTER(FloppyDrives) (ComSafeArrayOut (IHostFloppyDrive *, aDrives))
439{
440 CheckComArgOutPointerValid(aDrives);
441 AutoWriteLock alock (this);
442 CHECK_READY();
443
444 std::list <ComObjPtr <HostFloppyDrive> > list;
445 HRESULT rc = S_OK;
446
447 try
448 {
449#ifdef RT_OS_WINDOWS
450 int sz = GetLogicalDriveStrings(0, NULL);
451 TCHAR *hostDrives = new TCHAR[sz+1];
452 GetLogicalDriveStrings(sz, hostDrives);
453 wchar_t driveName[3] = { '?', ':', '\0' };
454 TCHAR *p = hostDrives;
455 do
456 {
457 if (GetDriveType(p) == DRIVE_REMOVABLE)
458 {
459 driveName[0] = *p;
460 ComObjPtr <HostFloppyDrive> hostFloppyDriveObj;
461 hostFloppyDriveObj.createObject();
462 hostFloppyDriveObj->init (Bstr (driveName));
463 list.push_back (hostFloppyDriveObj);
464 }
465 p += _tcslen(p) + 1;
466 }
467 while (*p);
468 delete[] hostDrives;
469#elif defined(RT_OS_LINUX)
470 if (RT_SUCCESS (mHostDrives.updateFloppies()))
471 for (DriveInfoList::const_iterator it = mHostDrives.FloppyBegin();
472 SUCCEEDED (rc) && it != mHostDrives.FloppyEnd(); ++it)
473 {
474 ComObjPtr<HostFloppyDrive> hostFloppyDriveObj;
475 Bstr device(it->mDevice);
476 Bstr udi(it->mUdi);
477 Bstr description(it->mDescription);
478 if (SUCCEEDED (rc))
479 rc = hostFloppyDriveObj.createObject();
480 if (SUCCEEDED (rc))
481 rc = hostFloppyDriveObj->init (device, udi, description);
482 if (SUCCEEDED (rc))
483 list.push_back(hostFloppyDriveObj);
484 }
485#else
486 /* PORTME */
487#endif
488
489 SafeIfaceArray<IHostFloppyDrive> collection (list);
490 collection.detachTo(ComSafeArrayOutArg (aDrives));
491 }
492 catch(std::bad_alloc &e)
493 {
494 rc = E_OUTOFMEMORY;
495 }
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 NOREF(aUSBDevices);
1008# ifndef RT_OS_WINDOWS
1009 NOREF(aUSBDevicesSize);
1010# endif
1011 ReturnComNotImplemented();
1012#endif
1013}
1014
1015STDMETHODIMP Host::COMGETTER(USBDeviceFilters) (ComSafeArrayOut (IHostUSBDeviceFilter *, aUSBDeviceFilters))
1016{
1017#ifdef VBOX_WITH_USB
1018 CheckComArgOutSafeArrayPointerValid(aUSBDeviceFilters);
1019
1020 AutoWriteLock alock (this);
1021 CHECK_READY();
1022
1023 MultiResult rc = checkUSBProxyService();
1024 CheckComRCReturnRC (rc);
1025
1026 SafeIfaceArray <IHostUSBDeviceFilter> collection (mUSBDeviceFilters);
1027 collection.detachTo (ComSafeArrayOutArg (aUSBDeviceFilters));
1028
1029 return rc;
1030#else
1031 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1032 * extended error info to indicate that USB is simply not available
1033 * (w/o treating it as a failure), for example, as in OSE. */
1034 NOREF(aUSBDeviceFilters);
1035# ifndef RT_OS_WINDOWS
1036 NOREF(aUSBDeviceFiltersSize);
1037# endif
1038 ReturnComNotImplemented();
1039#endif
1040}
1041
1042/**
1043 * Returns the number of installed logical processors
1044 *
1045 * @returns COM status code
1046 * @param count address of result variable
1047 */
1048STDMETHODIMP Host::COMGETTER(ProcessorCount)(ULONG *aCount)
1049{
1050 CheckComArgOutPointerValid(aCount);
1051 AutoWriteLock alock (this);
1052 CHECK_READY();
1053 *aCount = RTMpGetPresentCount();
1054 return S_OK;
1055}
1056
1057/**
1058 * Returns the number of online logical processors
1059 *
1060 * @returns COM status code
1061 * @param count address of result variable
1062 */
1063STDMETHODIMP Host::COMGETTER(ProcessorOnlineCount)(ULONG *aCount)
1064{
1065 CheckComArgOutPointerValid(aCount);
1066 AutoWriteLock alock (this);
1067 CHECK_READY();
1068 *aCount = RTMpGetOnlineCount();
1069 return S_OK;
1070}
1071
1072/**
1073 * Returns the (approximate) maximum speed of the given host CPU in MHz
1074 *
1075 * @returns COM status code
1076 * @param cpu id to get info for.
1077 * @param speed address of result variable, speed is 0 if unknown or aCpuId is invalid.
1078 */
1079STDMETHODIMP Host::GetProcessorSpeed(ULONG aCpuId, ULONG *aSpeed)
1080{
1081 CheckComArgOutPointerValid(aSpeed);
1082 AutoWriteLock alock (this);
1083 CHECK_READY();
1084 *aSpeed = RTMpGetMaxFrequency(aCpuId);
1085 return S_OK;
1086}
1087/**
1088 * Returns a description string for the host CPU
1089 *
1090 * @returns COM status code
1091 * @param cpu id to get info for.
1092 * @param description address of result variable, empty string if not known or aCpuId is invalid.
1093 */
1094STDMETHODIMP Host::GetProcessorDescription(ULONG /* aCpuId */, BSTR *aDescription)
1095{
1096 CheckComArgOutPointerValid(aDescription);
1097 AutoWriteLock alock (this);
1098 CHECK_READY();
1099 /** @todo */
1100 ReturnComNotImplemented();
1101}
1102
1103/**
1104 * Returns whether a host processor feature is supported or not
1105 *
1106 * @returns COM status code
1107 * @param Feature to query.
1108 * @param address of supported bool result variable
1109 */
1110STDMETHODIMP Host::GetProcessorFeature(ProcessorFeature_T aFeature, BOOL *aSupported)
1111{
1112 CheckComArgOutPointerValid(aSupported);
1113 AutoWriteLock alock (this);
1114 CHECK_READY();
1115
1116 switch (aFeature)
1117 {
1118 case ProcessorFeature_HWVirtEx:
1119 *aSupported = fVTxAMDVSupported;
1120 break;
1121
1122 case ProcessorFeature_PAE:
1123 *aSupported = fPAESupported;
1124 break;
1125
1126 case ProcessorFeature_LongMode:
1127 *aSupported = fLongModeSupported;
1128 break;
1129
1130 default:
1131 ReturnComNotImplemented();
1132 }
1133 return S_OK;
1134}
1135
1136/**
1137 * Returns the amount of installed system memory in megabytes
1138 *
1139 * @returns COM status code
1140 * @param size address of result variable
1141 */
1142STDMETHODIMP Host::COMGETTER(MemorySize)(ULONG *aSize)
1143{
1144 CheckComArgOutPointerValid(aSize);
1145 AutoWriteLock alock (this);
1146 CHECK_READY();
1147 /* @todo This is an ugly hack. There must be a function in IPRT for that. */
1148 pm::CollectorHAL *hal = pm::createHAL();
1149 if (!hal)
1150 return E_FAIL;
1151 ULONG tmp;
1152 int rc = hal->getHostMemoryUsage(aSize, &tmp, &tmp);
1153 *aSize /= 1024;
1154 delete hal;
1155 return rc;
1156}
1157
1158/**
1159 * Returns the current system memory free space in megabytes
1160 *
1161 * @returns COM status code
1162 * @param available address of result variable
1163 */
1164STDMETHODIMP Host::COMGETTER(MemoryAvailable)(ULONG *aAvailable)
1165{
1166 CheckComArgOutPointerValid(aAvailable);
1167 AutoWriteLock alock (this);
1168 CHECK_READY();
1169 /* @todo This is an ugly hack. There must be a function in IPRT for that. */
1170 pm::CollectorHAL *hal = pm::createHAL();
1171 if (!hal)
1172 return E_FAIL;
1173 ULONG tmp;
1174 int rc = hal->getHostMemoryUsage(&tmp, &tmp, aAvailable);
1175 *aAvailable /= 1024;
1176 delete hal;
1177 return rc;
1178}
1179
1180/**
1181 * Returns the name string of the host operating system
1182 *
1183 * @returns COM status code
1184 * @param os address of result variable
1185 */
1186STDMETHODIMP Host::COMGETTER(OperatingSystem)(BSTR *aOs)
1187{
1188 CheckComArgOutPointerValid(aOs);
1189 AutoWriteLock alock (this);
1190 CHECK_READY();
1191
1192 char szOSName[80];
1193 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szOSName, sizeof(szOSName));
1194 if (RT_FAILURE(vrc))
1195 return E_FAIL; /** @todo error reporting? */
1196 Bstr (szOSName).cloneTo (aOs);
1197 return S_OK;
1198}
1199
1200/**
1201 * Returns the version string of the host operating system
1202 *
1203 * @returns COM status code
1204 * @param os address of result variable
1205 */
1206STDMETHODIMP Host::COMGETTER(OSVersion)(BSTR *aVersion)
1207{
1208 CheckComArgOutPointerValid(aVersion);
1209 AutoWriteLock alock (this);
1210 CHECK_READY();
1211
1212 /* Get the OS release. Reserve some buffer space for the service pack. */
1213 char szOSRelease[128];
1214 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOSRelease, sizeof(szOSRelease) - 32);
1215 if (RT_FAILURE(vrc))
1216 return E_FAIL; /** @todo error reporting? */
1217
1218 /* Append the service pack if present. */
1219 char szOSServicePack[80];
1220 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szOSServicePack, sizeof(szOSServicePack));
1221 if (RT_FAILURE(vrc))
1222 {
1223 if (vrc != VERR_NOT_SUPPORTED)
1224 return E_FAIL; /** @todo error reporting? */
1225 szOSServicePack[0] = '\0';
1226 }
1227 if (szOSServicePack[0] != '\0')
1228 {
1229 char *psz = strchr(szOSRelease, '\0');
1230 RTStrPrintf(psz, &szOSRelease[sizeof(szOSRelease)] - psz, "sp%s", szOSServicePack);
1231 }
1232
1233 Bstr (szOSRelease).cloneTo (aVersion);
1234 return S_OK;
1235}
1236
1237/**
1238 * Returns the current host time in milliseconds since 1970-01-01 UTC.
1239 *
1240 * @returns COM status code
1241 * @param time address of result variable
1242 */
1243STDMETHODIMP Host::COMGETTER(UTCTime)(LONG64 *aUTCTime)
1244{
1245 CheckComArgOutPointerValid(aUTCTime);
1246 AutoWriteLock alock (this);
1247 CHECK_READY();
1248 RTTIMESPEC now;
1249 *aUTCTime = RTTimeSpecGetMilli(RTTimeNow(&now));
1250 return S_OK;
1251}
1252
1253STDMETHODIMP Host::COMGETTER(Acceleration3DAvailable)(BOOL *aSupported)
1254{
1255 CheckComArgOutPointerValid(aSupported);
1256
1257 AutoWriteLock alock(this);
1258 CHECK_READY();
1259
1260 *aSupported = f3DAccelerationSupported;
1261
1262 return S_OK;
1263}
1264
1265// IHost methods
1266////////////////////////////////////////////////////////////////////////////////
1267STDMETHODIMP
1268Host::CreateHostOnlyNetworkInterface (IHostNetworkInterface **aHostNetworkInterface,
1269 IProgress **aProgress)
1270{
1271 CheckComArgOutPointerValid(aHostNetworkInterface);
1272 CheckComArgOutPointerValid(aProgress);
1273
1274 AutoWriteLock alock (this);
1275 CHECK_READY();
1276
1277 int r = NetIfCreateHostOnlyNetworkInterface (mParent, aHostNetworkInterface, aProgress);
1278 if(RT_SUCCESS(r))
1279 {
1280 return S_OK;
1281 }
1282
1283 return r == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
1284}
1285
1286STDMETHODIMP
1287Host::RemoveHostOnlyNetworkInterface (IN_BSTR aId,
1288 IHostNetworkInterface **aHostNetworkInterface,
1289 IProgress **aProgress)
1290{
1291 CheckComArgOutPointerValid(aHostNetworkInterface);
1292 CheckComArgOutPointerValid(aProgress);
1293
1294 AutoWriteLock alock (this);
1295 CHECK_READY();
1296
1297 /* first check whether an interface with the given name already exists */
1298 {
1299 ComPtr <IHostNetworkInterface> iface;
1300 if (FAILED (FindHostNetworkInterfaceById (aId, iface.asOutParam())))
1301 return setError (VBOX_E_OBJECT_NOT_FOUND,
1302 tr ("Host network interface with UUID {%RTuuid} does not exist"),
1303 Guid (aId).raw());
1304 }
1305
1306 int r = NetIfRemoveHostOnlyNetworkInterface (mParent, Guid(aId), aHostNetworkInterface, aProgress);
1307 if(RT_SUCCESS(r))
1308 {
1309 return S_OK;
1310 }
1311
1312 return r == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
1313}
1314
1315STDMETHODIMP Host::CreateUSBDeviceFilter (IN_BSTR aName, IHostUSBDeviceFilter **aFilter)
1316{
1317#ifdef VBOX_WITH_USB
1318 CheckComArgStrNotEmptyOrNull(aName);
1319 CheckComArgOutPointerValid(aFilter);
1320
1321 AutoWriteLock alock (this);
1322 CHECK_READY();
1323
1324 ComObjPtr <HostUSBDeviceFilter> filter;
1325 filter.createObject();
1326 HRESULT rc = filter->init (this, aName);
1327 ComAssertComRCRet (rc, rc);
1328 rc = filter.queryInterfaceTo (aFilter);
1329 AssertComRCReturn (rc, rc);
1330 return S_OK;
1331#else
1332 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1333 * extended error info to indicate that USB is simply not available
1334 * (w/o treating it as a failure), for example, as in OSE. */
1335 NOREF(aName);
1336 NOREF(aFilter);
1337 ReturnComNotImplemented();
1338#endif
1339}
1340
1341STDMETHODIMP Host::InsertUSBDeviceFilter (ULONG aPosition, IHostUSBDeviceFilter *aFilter)
1342{
1343#ifdef VBOX_WITH_USB
1344 CheckComArgNotNull(aFilter);
1345
1346 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1347 AutoWriteLock alock (this);
1348 CHECK_READY();
1349
1350 MultiResult rc = checkUSBProxyService();
1351 CheckComRCReturnRC (rc);
1352
1353 ComObjPtr <HostUSBDeviceFilter> filter = getDependentChild (aFilter);
1354 if (!filter)
1355 return setError (VBOX_E_INVALID_OBJECT_STATE,
1356 tr ("The given USB device filter is not created within "
1357 "this VirtualBox instance"));
1358
1359 if (filter->mInList)
1360 return setError (E_INVALIDARG,
1361 tr ("The given USB device filter is already in the list"));
1362
1363 /* iterate to the position... */
1364 USBDeviceFilterList::iterator it = mUSBDeviceFilters.begin();
1365 std::advance (it, aPosition);
1366 /* ...and insert */
1367 mUSBDeviceFilters.insert (it, filter);
1368 filter->mInList = true;
1369
1370 /* notify the proxy (only when the filter is active) */
1371 if (mUSBProxyService->isActive() && filter->data().mActive)
1372 {
1373 ComAssertRet (filter->id() == NULL, E_FAIL);
1374 filter->id() = mUSBProxyService->insertFilter (&filter->data().mUSBFilter);
1375 }
1376
1377 /* save the global settings */
1378 alock.unlock();
1379 return rc = mParent->saveSettings();
1380#else
1381 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1382 * extended error info to indicate that USB is simply not available
1383 * (w/o treating it as a failure), for example, as in OSE. */
1384 NOREF(aPosition);
1385 NOREF(aFilter);
1386 ReturnComNotImplemented();
1387#endif
1388}
1389
1390STDMETHODIMP Host::RemoveUSBDeviceFilter (ULONG aPosition, IHostUSBDeviceFilter **aFilter)
1391{
1392#ifdef VBOX_WITH_USB
1393 CheckComArgOutPointerValid(aFilter);
1394
1395 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1396 AutoWriteLock alock (this);
1397 CHECK_READY();
1398
1399 MultiResult rc = checkUSBProxyService();
1400 CheckComRCReturnRC (rc);
1401
1402 if (!mUSBDeviceFilters.size())
1403 return setError (E_INVALIDARG,
1404 tr ("The USB device filter list is empty"));
1405
1406 if (aPosition >= mUSBDeviceFilters.size())
1407 return setError (E_INVALIDARG,
1408 tr ("Invalid position: %lu (must be in range [0, %lu])"),
1409 aPosition, mUSBDeviceFilters.size() - 1);
1410
1411 ComObjPtr <HostUSBDeviceFilter> filter;
1412 {
1413 /* iterate to the position... */
1414 USBDeviceFilterList::iterator it = mUSBDeviceFilters.begin();
1415 std::advance (it, aPosition);
1416 /* ...get an element from there... */
1417 filter = *it;
1418 /* ...and remove */
1419 filter->mInList = false;
1420 mUSBDeviceFilters.erase (it);
1421 }
1422
1423 filter.queryInterfaceTo (aFilter);
1424
1425 /* notify the proxy (only when the filter is active) */
1426 if (mUSBProxyService->isActive() && filter->data().mActive)
1427 {
1428 ComAssertRet (filter->id() != NULL, E_FAIL);
1429 mUSBProxyService->removeFilter (filter->id());
1430 filter->id() = NULL;
1431 }
1432
1433 /* save the global settings */
1434 alock.unlock();
1435 return rc = mParent->saveSettings();
1436#else
1437 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1438 * extended error info to indicate that USB is simply not available
1439 * (w/o treating it as a failure), for example, as in OSE. */
1440 NOREF(aPosition);
1441 NOREF(aFilter);
1442 ReturnComNotImplemented();
1443#endif
1444}
1445
1446// public methods only for internal purposes
1447////////////////////////////////////////////////////////////////////////////////
1448
1449HRESULT Host::loadSettings (const settings::Key &aGlobal)
1450{
1451 using namespace settings;
1452
1453 AutoWriteLock alock (this);
1454 CHECK_READY();
1455
1456 AssertReturn (!aGlobal.isNull(), E_FAIL);
1457
1458 HRESULT rc = S_OK;
1459
1460#ifdef VBOX_WITH_USB
1461 Key::List filters = aGlobal.key ("USBDeviceFilters").keys ("DeviceFilter");
1462 for (Key::List::const_iterator it = filters.begin();
1463 it != filters.end(); ++ it)
1464 {
1465 Bstr name = (*it).stringValue ("name");
1466 bool active = (*it).value <bool> ("active");
1467
1468 Bstr vendorId = (*it).stringValue ("vendorId");
1469 Bstr productId = (*it).stringValue ("productId");
1470 Bstr revision = (*it).stringValue ("revision");
1471 Bstr manufacturer = (*it).stringValue ("manufacturer");
1472 Bstr product = (*it).stringValue ("product");
1473 Bstr serialNumber = (*it).stringValue ("serialNumber");
1474 Bstr port = (*it).stringValue ("port");
1475
1476 USBDeviceFilterAction_T action;
1477 action = USBDeviceFilterAction_Ignore;
1478 const char *actionStr = (*it).stringValue ("action");
1479 if (strcmp (actionStr, "Ignore") == 0)
1480 action = USBDeviceFilterAction_Ignore;
1481 else
1482 if (strcmp (actionStr, "Hold") == 0)
1483 action = USBDeviceFilterAction_Hold;
1484 else
1485 AssertMsgFailed (("Invalid action: '%s'\n", actionStr));
1486
1487 ComObjPtr <HostUSBDeviceFilter> filterObj;
1488 filterObj.createObject();
1489 rc = filterObj->init (this,
1490 name, active, vendorId, productId, revision,
1491 manufacturer, product, serialNumber, port,
1492 action);
1493 /* error info is set by init() when appropriate */
1494 CheckComRCBreakRC (rc);
1495
1496 mUSBDeviceFilters.push_back (filterObj);
1497 filterObj->mInList = true;
1498
1499 /* notify the proxy (only when the filter is active) */
1500 if (filterObj->data().mActive)
1501 {
1502 HostUSBDeviceFilter *flt = filterObj; /* resolve ambiguity */
1503 flt->id() = mUSBProxyService->insertFilter (&filterObj->data().mUSBFilter);
1504 }
1505 }
1506#endif /* VBOX_WITH_USB */
1507
1508 return rc;
1509}
1510
1511HRESULT Host::saveSettings (settings::Key &aGlobal)
1512{
1513 using namespace settings;
1514
1515 AutoWriteLock alock (this);
1516 CHECK_READY();
1517
1518 ComAssertRet (!aGlobal.isNull(), E_FAIL);
1519
1520#ifdef VBOX_WITH_USB
1521 /* first, delete the entry */
1522 Key filters = aGlobal.findKey ("USBDeviceFilters");
1523 if (!filters.isNull())
1524 filters.zap();
1525 /* then, recreate it */
1526 filters = aGlobal.createKey ("USBDeviceFilters");
1527
1528 USBDeviceFilterList::const_iterator it = mUSBDeviceFilters.begin();
1529 while (it != mUSBDeviceFilters.end())
1530 {
1531 AutoWriteLock filterLock (*it);
1532 const HostUSBDeviceFilter::Data &data = (*it)->data();
1533
1534 Key filter = filters.appendKey ("DeviceFilter");
1535
1536 filter.setValue <Bstr> ("name", data.mName);
1537 filter.setValue <bool> ("active", !!data.mActive);
1538
1539 /* all are optional */
1540 Bstr str;
1541 (*it)->COMGETTER (VendorId) (str.asOutParam());
1542 if (!str.isNull())
1543 filter.setValue <Bstr> ("vendorId", str);
1544
1545 (*it)->COMGETTER (ProductId) (str.asOutParam());
1546 if (!str.isNull())
1547 filter.setValue <Bstr> ("productId", str);
1548
1549 (*it)->COMGETTER (Revision) (str.asOutParam());
1550 if (!str.isNull())
1551 filter.setValue <Bstr> ("revision", str);
1552
1553 (*it)->COMGETTER (Manufacturer) (str.asOutParam());
1554 if (!str.isNull())
1555 filter.setValue <Bstr> ("manufacturer", str);
1556
1557 (*it)->COMGETTER (Product) (str.asOutParam());
1558 if (!str.isNull())
1559 filter.setValue <Bstr> ("product", str);
1560
1561 (*it)->COMGETTER (SerialNumber) (str.asOutParam());
1562 if (!str.isNull())
1563 filter.setValue <Bstr> ("serialNumber", str);
1564
1565 (*it)->COMGETTER (Port) (str.asOutParam());
1566 if (!str.isNull())
1567 filter.setValue <Bstr> ("port", str);
1568
1569 /* action is mandatory */
1570 USBDeviceFilterAction_T action = USBDeviceFilterAction_Null;
1571 (*it)->COMGETTER (Action) (&action);
1572 if (action == USBDeviceFilterAction_Ignore)
1573 filter.setStringValue ("action", "Ignore");
1574 else if (action == USBDeviceFilterAction_Hold)
1575 filter.setStringValue ("action", "Hold");
1576 else
1577 AssertMsgFailed (("Invalid action: %d\n", action));
1578
1579 ++ it;
1580 }
1581#endif /* VBOX_WITH_USB */
1582
1583 return S_OK;
1584}
1585
1586#ifdef VBOX_WITH_USB
1587/**
1588 * Called by setter methods of all USB device filters.
1589 */
1590HRESULT Host::onUSBDeviceFilterChange (HostUSBDeviceFilter *aFilter,
1591 BOOL aActiveChanged /* = FALSE */)
1592{
1593 AutoWriteLock alock (this);
1594 CHECK_READY();
1595
1596 if (aFilter->mInList)
1597 {
1598 if (aActiveChanged)
1599 {
1600 // insert/remove the filter from the proxy
1601 if (aFilter->data().mActive)
1602 {
1603 ComAssertRet (aFilter->id() == NULL, E_FAIL);
1604 aFilter->id() = mUSBProxyService->insertFilter (&aFilter->data().mUSBFilter);
1605 }
1606 else
1607 {
1608 ComAssertRet (aFilter->id() != NULL, E_FAIL);
1609 mUSBProxyService->removeFilter (aFilter->id());
1610 aFilter->id() = NULL;
1611 }
1612 }
1613 else
1614 {
1615 if (aFilter->data().mActive)
1616 {
1617 // update the filter in the proxy
1618 ComAssertRet (aFilter->id() != NULL, E_FAIL);
1619 mUSBProxyService->removeFilter (aFilter->id());
1620 aFilter->id() = mUSBProxyService->insertFilter (&aFilter->data().mUSBFilter);
1621 }
1622 }
1623
1624 // save the global settings... yeah, on every single filter property change
1625 alock.unlock();
1626 return mParent->saveSettings();
1627 }
1628
1629 return S_OK;
1630}
1631
1632
1633/**
1634 * Interface for obtaining a copy of the USBDeviceFilterList,
1635 * used by the USBProxyService.
1636 *
1637 * @param aGlobalFilters Where to put the global filter list copy.
1638 * @param aMachines Where to put the machine vector.
1639 */
1640void Host::getUSBFilters(Host::USBDeviceFilterList *aGlobalFilters, VirtualBox::SessionMachineVector *aMachines)
1641{
1642 AutoWriteLock alock (this);
1643
1644 mParent->getOpenedMachines (*aMachines);
1645 *aGlobalFilters = mUSBDeviceFilters;
1646}
1647
1648#endif /* VBOX_WITH_USB */
1649
1650// private methods
1651////////////////////////////////////////////////////////////////////////////////
1652
1653#if (defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)) && defined(VBOX_USE_LIBHAL)
1654/* Solaris and FreeBSD hosts, loading libhal at runtime */
1655
1656/**
1657 * Helper function to query the hal subsystem for information about DVD drives attached to the
1658 * system.
1659 *
1660 * @returns true if information was successfully obtained, false otherwise
1661 * @retval list drives found will be attached to this list
1662 */
1663bool Host::getDVDInfoFromHal(std::list <ComObjPtr <HostDVDDrive> > &list)
1664{
1665 bool halSuccess = false;
1666 DBusError dbusError;
1667 if (!gLibHalCheckPresence())
1668 return false;
1669 gDBusErrorInit (&dbusError);
1670 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
1671 if (dbusConnection != 0)
1672 {
1673 LibHalContext *halContext = gLibHalCtxNew();
1674 if (halContext != 0)
1675 {
1676 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
1677 {
1678 if (gLibHalCtxInit(halContext, &dbusError))
1679 {
1680 int numDevices;
1681 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
1682 "storage.drive_type", "cdrom",
1683 &numDevices, &dbusError);
1684 if (halDevices != 0)
1685 {
1686 /* Hal is installed and working, so if no devices are reported, assume
1687 that there are none. */
1688 halSuccess = true;
1689 for (int i = 0; i < numDevices; i++)
1690 {
1691 char *devNode = gLibHalDeviceGetPropertyString(halContext,
1692 halDevices[i], "block.device", &dbusError);
1693#ifdef RT_OS_SOLARIS
1694 /* The CD/DVD ioctls work only for raw device nodes. */
1695 char *tmp = getfullrawname(devNode);
1696 gLibHalFreeString(devNode);
1697 devNode = tmp;
1698#endif
1699
1700#ifdef RT_OS_FREEBSD
1701 /*
1702 * Don't show devices handled by the 'acd' driver.
1703 * The ioctls don't work with it.
1704 */
1705 char *driverName = gLibHalDeviceGetPropertyString(halContext,
1706 halDevices[i], "freebsd.driver", &dbusError);
1707 if (driverName)
1708 {
1709 if (RTStrCmp(driverName, "acd") == 0)
1710 {
1711 gLibHalFreeString(devNode);
1712 devNode = NULL;
1713 }
1714 gLibHalFreeString(driverName);
1715 }
1716#endif
1717
1718 if (devNode != 0)
1719 {
1720// if (validateDevice(devNode, true))
1721// {
1722 Utf8Str description;
1723 char *vendor, *product;
1724 /* We do not check the error here, as this field may
1725 not even exist. */
1726 vendor = gLibHalDeviceGetPropertyString(halContext,
1727 halDevices[i], "info.vendor", 0);
1728 product = gLibHalDeviceGetPropertyString(halContext,
1729 halDevices[i], "info.product", &dbusError);
1730 if ((product != 0 && product[0] != 0))
1731 {
1732 if ((vendor != 0) && (vendor[0] != 0))
1733 {
1734 description = Utf8StrFmt ("%s %s",
1735 vendor, product);
1736 }
1737 else
1738 {
1739 description = product;
1740 }
1741 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
1742 hostDVDDriveObj.createObject();
1743 hostDVDDriveObj->init (Bstr (devNode),
1744 Bstr (halDevices[i]),
1745 Bstr (description));
1746 list.push_back (hostDVDDriveObj);
1747 }
1748 else
1749 {
1750 if (product == 0)
1751 {
1752 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
1753 halDevices[i], dbusError.name, dbusError.message));
1754 gDBusErrorFree(&dbusError);
1755 }
1756 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
1757 hostDVDDriveObj.createObject();
1758 hostDVDDriveObj->init (Bstr (devNode),
1759 Bstr (halDevices[i]));
1760 list.push_back (hostDVDDriveObj);
1761 }
1762 if (vendor != 0)
1763 {
1764 gLibHalFreeString(vendor);
1765 }
1766 if (product != 0)
1767 {
1768 gLibHalFreeString(product);
1769 }
1770// }
1771// else
1772// {
1773// LogRel(("Host::COMGETTER(DVDDrives): failed to validate the block device %s as a DVD drive\n"));
1774// }
1775#ifndef RT_OS_SOLARIS
1776 gLibHalFreeString(devNode);
1777#else
1778 free(devNode);
1779#endif
1780 }
1781 else
1782 {
1783 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
1784 halDevices[i], dbusError.name, dbusError.message));
1785 gDBusErrorFree(&dbusError);
1786 }
1787 }
1788 gLibHalFreeStringArray(halDevices);
1789 }
1790 else
1791 {
1792 LogRel(("Host::COMGETTER(DVDDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1793 gDBusErrorFree(&dbusError);
1794 }
1795 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
1796 {
1797 LogRel(("Host::COMGETTER(DVDDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1798 gDBusErrorFree(&dbusError);
1799 }
1800 }
1801 else
1802 {
1803 LogRel(("Host::COMGETTER(DVDDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1804 gDBusErrorFree(&dbusError);
1805 }
1806 gLibHalCtxFree(halContext);
1807 }
1808 else
1809 {
1810 LogRel(("Host::COMGETTER(DVDDrives): failed to set libhal connection to dbus.\n"));
1811 }
1812 }
1813 else
1814 {
1815 LogRel(("Host::COMGETTER(DVDDrives): failed to get a libhal context - out of memory?\n"));
1816 }
1817 gDBusConnectionUnref(dbusConnection);
1818 }
1819 else
1820 {
1821 LogRel(("Host::COMGETTER(DVDDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1822 gDBusErrorFree(&dbusError);
1823 }
1824 return halSuccess;
1825}
1826
1827
1828/**
1829 * Helper function to query the hal subsystem for information about floppy drives attached to the
1830 * system.
1831 *
1832 * @returns true if information was successfully obtained, false otherwise
1833 * @retval list drives found will be attached to this list
1834 */
1835bool Host::getFloppyInfoFromHal(std::list <ComObjPtr <HostFloppyDrive> > &list)
1836{
1837 bool halSuccess = false;
1838 DBusError dbusError;
1839 if (!gLibHalCheckPresence())
1840 return false;
1841 gDBusErrorInit (&dbusError);
1842 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
1843 if (dbusConnection != 0)
1844 {
1845 LibHalContext *halContext = gLibHalCtxNew();
1846 if (halContext != 0)
1847 {
1848 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
1849 {
1850 if (gLibHalCtxInit(halContext, &dbusError))
1851 {
1852 int numDevices;
1853 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
1854 "storage.drive_type", "floppy",
1855 &numDevices, &dbusError);
1856 if (halDevices != 0)
1857 {
1858 /* Hal is installed and working, so if no devices are reported, assume
1859 that there are none. */
1860 halSuccess = true;
1861 for (int i = 0; i < numDevices; i++)
1862 {
1863 char *driveType = gLibHalDeviceGetPropertyString(halContext,
1864 halDevices[i], "storage.drive_type", 0);
1865 if (driveType != 0)
1866 {
1867 if (strcmp(driveType, "floppy") != 0)
1868 {
1869 gLibHalFreeString(driveType);
1870 continue;
1871 }
1872 gLibHalFreeString(driveType);
1873 }
1874 else
1875 {
1876 /* An error occurred. The attribute "storage.drive_type"
1877 probably didn't exist. */
1878 continue;
1879 }
1880 char *devNode = gLibHalDeviceGetPropertyString(halContext,
1881 halDevices[i], "block.device", &dbusError);
1882 if (devNode != 0)
1883 {
1884// if (validateDevice(devNode, false))
1885// {
1886 Utf8Str description;
1887 char *vendor, *product;
1888 /* We do not check the error here, as this field may
1889 not even exist. */
1890 vendor = gLibHalDeviceGetPropertyString(halContext,
1891 halDevices[i], "info.vendor", 0);
1892 product = gLibHalDeviceGetPropertyString(halContext,
1893 halDevices[i], "info.product", &dbusError);
1894 if ((product != 0) && (product[0] != 0))
1895 {
1896 if ((vendor != 0) && (vendor[0] != 0))
1897 {
1898 description = Utf8StrFmt ("%s %s",
1899 vendor, product);
1900 }
1901 else
1902 {
1903 description = product;
1904 }
1905 ComObjPtr <HostFloppyDrive> hostFloppyDrive;
1906 hostFloppyDrive.createObject();
1907 hostFloppyDrive->init (Bstr (devNode),
1908 Bstr (halDevices[i]),
1909 Bstr (description));
1910 list.push_back (hostFloppyDrive);
1911 }
1912 else
1913 {
1914 if (product == 0)
1915 {
1916 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
1917 halDevices[i], dbusError.name, dbusError.message));
1918 gDBusErrorFree(&dbusError);
1919 }
1920 ComObjPtr <HostFloppyDrive> hostFloppyDrive;
1921 hostFloppyDrive.createObject();
1922 hostFloppyDrive->init (Bstr (devNode),
1923 Bstr (halDevices[i]));
1924 list.push_back (hostFloppyDrive);
1925 }
1926 if (vendor != 0)
1927 {
1928 gLibHalFreeString(vendor);
1929 }
1930 if (product != 0)
1931 {
1932 gLibHalFreeString(product);
1933 }
1934// }
1935// else
1936// {
1937// LogRel(("Host::COMGETTER(FloppyDrives): failed to validate the block device %s as a floppy drive\n"));
1938// }
1939 gLibHalFreeString(devNode);
1940 }
1941 else
1942 {
1943 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
1944 halDevices[i], dbusError.name, dbusError.message));
1945 gDBusErrorFree(&dbusError);
1946 }
1947 }
1948 gLibHalFreeStringArray(halDevices);
1949 }
1950 else
1951 {
1952 LogRel(("Host::COMGETTER(FloppyDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1953 gDBusErrorFree(&dbusError);
1954 }
1955 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
1956 {
1957 LogRel(("Host::COMGETTER(FloppyDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1958 gDBusErrorFree(&dbusError);
1959 }
1960 }
1961 else
1962 {
1963 LogRel(("Host::COMGETTER(FloppyDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1964 gDBusErrorFree(&dbusError);
1965 }
1966 gLibHalCtxFree(halContext);
1967 }
1968 else
1969 {
1970 LogRel(("Host::COMGETTER(FloppyDrives): failed to set libhal connection to dbus.\n"));
1971 }
1972 }
1973 else
1974 {
1975 LogRel(("Host::COMGETTER(FloppyDrives): failed to get a libhal context - out of memory?\n"));
1976 }
1977 gDBusConnectionUnref(dbusConnection);
1978 }
1979 else
1980 {
1981 LogRel(("Host::COMGETTER(FloppyDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1982 gDBusErrorFree(&dbusError);
1983 }
1984 return halSuccess;
1985}
1986#endif /* RT_OS_SOLARIS and VBOX_USE_HAL */
1987
1988#if defined(RT_OS_SOLARIS)
1989
1990/**
1991 * Helper function to parse the given mount file and add found entries
1992 */
1993void Host::parseMountTable(char *mountTable, std::list <ComObjPtr <HostDVDDrive> > &list)
1994{
1995#ifdef RT_OS_LINUX
1996 FILE *mtab = setmntent(mountTable, "r");
1997 if (mtab)
1998 {
1999 struct mntent *mntent;
2000 char *mnt_type;
2001 char *mnt_dev;
2002 char *tmp;
2003 while ((mntent = getmntent(mtab)))
2004 {
2005 mnt_type = (char*)malloc(strlen(mntent->mnt_type) + 1);
2006 mnt_dev = (char*)malloc(strlen(mntent->mnt_fsname) + 1);
2007 strcpy(mnt_type, mntent->mnt_type);
2008 strcpy(mnt_dev, mntent->mnt_fsname);
2009 // supermount fs case
2010 if (strcmp(mnt_type, "supermount") == 0)
2011 {
2012 tmp = strstr(mntent->mnt_opts, "fs=");
2013 if (tmp)
2014 {
2015 free(mnt_type);
2016 mnt_type = strdup(tmp + strlen("fs="));
2017 if (mnt_type)
2018 {
2019 tmp = strchr(mnt_type, ',');
2020 if (tmp)
2021 *tmp = '\0';
2022 }
2023 }
2024 tmp = strstr(mntent->mnt_opts, "dev=");
2025 if (tmp)
2026 {
2027 free(mnt_dev);
2028 mnt_dev = strdup(tmp + strlen("dev="));
2029 if (mnt_dev)
2030 {
2031 tmp = strchr(mnt_dev, ',');
2032 if (tmp)
2033 *tmp = '\0';
2034 }
2035 }
2036 }
2037 // use strstr here to cover things fs types like "udf,iso9660"
2038 if (strstr(mnt_type, "iso9660") == 0)
2039 {
2040 /** @todo check whether we've already got the drive in our list! */
2041 if (validateDevice(mnt_dev, true))
2042 {
2043 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
2044 hostDVDDriveObj.createObject();
2045 hostDVDDriveObj->init (Bstr (mnt_dev));
2046 list.push_back (hostDVDDriveObj);
2047 }
2048 }
2049 free(mnt_dev);
2050 free(mnt_type);
2051 }
2052 endmntent(mtab);
2053 }
2054#else // RT_OS_SOLARIS
2055 FILE *mntFile = fopen(mountTable, "r");
2056 if (mntFile)
2057 {
2058 struct mnttab mntTab;
2059 while (getmntent(mntFile, &mntTab) == 0)
2060 {
2061 char *mountName = strdup(mntTab.mnt_special);
2062 char *mountPoint = strdup(mntTab.mnt_mountp);
2063 char *mountFSType = strdup(mntTab.mnt_fstype);
2064
2065 // skip devices we are not interested in
2066 if ((*mountName && mountName[0] == '/') && // skip 'fake' devices (like -hosts, proc, fd, swap)
2067 (*mountFSType && (strcmp(mountFSType, "devfs") != 0 && // skip devfs (i.e. /devices)
2068 strcmp(mountFSType, "dev") != 0 && // skip dev (i.e. /dev)
2069 strcmp(mountFSType, "lofs") != 0)) && // skip loop-back file-system (lofs)
2070 (*mountPoint && strcmp(mountPoint, "/") != 0)) // skip point '/' (Can CD/DVD be mounted at '/' ???)
2071 {
2072 char *rawDevName = getfullrawname(mountName);
2073 if (validateDevice(rawDevName, true))
2074 {
2075 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
2076 hostDVDDriveObj.createObject();
2077 hostDVDDriveObj->init (Bstr (rawDevName));
2078 list.push_back (hostDVDDriveObj);
2079 }
2080 free(rawDevName);
2081 }
2082
2083 free(mountName);
2084 free(mountPoint);
2085 free(mountFSType);
2086 }
2087
2088 fclose(mntFile);
2089 }
2090#endif
2091}
2092
2093/**
2094 * Helper function to check whether the given device node is a valid drive
2095 */
2096bool Host::validateDevice(const char *deviceNode, bool isCDROM)
2097{
2098 struct stat statInfo;
2099 bool retValue = false;
2100
2101 // sanity check
2102 if (!deviceNode)
2103 {
2104 return false;
2105 }
2106
2107 // first a simple stat() call
2108 if (stat(deviceNode, &statInfo) < 0)
2109 {
2110 return false;
2111 } else
2112 {
2113 if (isCDROM)
2114 {
2115 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2116 {
2117 int fileHandle;
2118 // now try to open the device
2119 fileHandle = open(deviceNode, O_RDONLY | O_NONBLOCK, 0);
2120 if (fileHandle >= 0)
2121 {
2122 cdrom_subchnl cdChannelInfo;
2123 cdChannelInfo.cdsc_format = CDROM_MSF;
2124 // this call will finally reveal the whole truth
2125#ifdef RT_OS_LINUX
2126 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2127 (errno == EIO) || (errno == ENOENT) ||
2128 (errno == EINVAL) || (errno == ENOMEDIUM))
2129#else
2130 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2131 (errno == EIO) || (errno == ENOENT) ||
2132 (errno == EINVAL))
2133#endif
2134 {
2135 retValue = true;
2136 }
2137 close(fileHandle);
2138 }
2139 }
2140 } else
2141 {
2142 // floppy case
2143 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2144 {
2145 /// @todo do some more testing, maybe a nice IOCTL!
2146 retValue = true;
2147 }
2148 }
2149 }
2150 return retValue;
2151}
2152#endif // RT_OS_SOLARIS
2153
2154#ifdef VBOX_WITH_USB
2155/**
2156 * Checks for the presense and status of the USB Proxy Service.
2157 * Returns S_OK when the Proxy is present and OK, VBOX_E_HOST_ERROR (as a
2158 * warning) if the proxy service is not available due to the way the host is
2159 * configured (at present, that means that usbfs and hal/DBus are not
2160 * available on a Linux host) or E_FAIL and a corresponding error message
2161 * otherwise. Intended to be used by methods that rely on the Proxy Service
2162 * availability.
2163 *
2164 * @note This method may return a warning result code. It is recommended to use
2165 * MultiError to store the return value.
2166 *
2167 * @note Locks this object for reading.
2168 */
2169HRESULT Host::checkUSBProxyService()
2170{
2171 AutoWriteLock alock (this);
2172 CHECK_READY();
2173
2174 AssertReturn (mUSBProxyService, E_FAIL);
2175 if (!mUSBProxyService->isActive())
2176 {
2177 /* disable the USB controller completely to avoid assertions if the
2178 * USB proxy service could not start. */
2179
2180 if (mUSBProxyService->getLastError() == VERR_FILE_NOT_FOUND)
2181 return setWarning (E_FAIL,
2182 tr ("Could not load the Host USB Proxy Service (%Rrc). "
2183 "The service might not be installed on the host computer"),
2184 mUSBProxyService->getLastError());
2185 if (mUSBProxyService->getLastError() == VINF_SUCCESS)
2186#ifdef RT_OS_LINUX
2187 return setWarning (VBOX_E_HOST_ERROR,
2188# ifdef VBOX_WITH_DBUS
2189 tr ("The USB Proxy Service could not be started, because neither the USB file system (usbfs) nor the hardware information service (hal) is available")
2190# else
2191 tr ("The USB Proxy Service could not be started, because the USB file system (usbfs) is not available")
2192# endif
2193 );
2194#else /* !RT_OS_LINUX */
2195 return setWarning (E_FAIL,
2196 tr ("The USB Proxy Service has not yet been ported to this host"));
2197#endif /* !RT_OS_LINUX */
2198 return setWarning (E_FAIL,
2199 tr ("Could not load the Host USB Proxy service (%Rrc)"),
2200 mUSBProxyService->getLastError());
2201 }
2202
2203 return S_OK;
2204}
2205#endif /* VBOX_WITH_USB */
2206
2207#ifdef VBOX_WITH_RESOURCE_USAGE_API
2208void Host::registerMetrics (PerformanceCollector *aCollector)
2209{
2210 pm::CollectorHAL *hal = aCollector->getHAL();
2211 /* Create sub metrics */
2212 pm::SubMetric *cpuLoadUser = new pm::SubMetric ("CPU/Load/User",
2213 "Percentage of processor time spent in user mode.");
2214 pm::SubMetric *cpuLoadKernel = new pm::SubMetric ("CPU/Load/Kernel",
2215 "Percentage of processor time spent in kernel mode.");
2216 pm::SubMetric *cpuLoadIdle = new pm::SubMetric ("CPU/Load/Idle",
2217 "Percentage of processor time spent idling.");
2218 pm::SubMetric *cpuMhzSM = new pm::SubMetric ("CPU/MHz",
2219 "Average of current frequency of all processors.");
2220 pm::SubMetric *ramUsageTotal = new pm::SubMetric ("RAM/Usage/Total",
2221 "Total physical memory installed.");
2222 pm::SubMetric *ramUsageUsed = new pm::SubMetric ("RAM/Usage/Used",
2223 "Physical memory currently occupied.");
2224 pm::SubMetric *ramUsageFree = new pm::SubMetric ("RAM/Usage/Free",
2225 "Physical memory currently available to applications.");
2226 /* Create and register base metrics */
2227 IUnknown *objptr;
2228 ComObjPtr <Host> tmp = this;
2229 tmp.queryInterfaceTo (&objptr);
2230 pm::BaseMetric *cpuLoad = new pm::HostCpuLoadRaw (hal, objptr, cpuLoadUser, cpuLoadKernel,
2231 cpuLoadIdle);
2232 aCollector->registerBaseMetric (cpuLoad);
2233 pm::BaseMetric *cpuMhz = new pm::HostCpuMhz (hal, objptr, cpuMhzSM);
2234 aCollector->registerBaseMetric (cpuMhz);
2235 pm::BaseMetric *ramUsage = new pm::HostRamUsage (hal, objptr, ramUsageTotal, ramUsageUsed,
2236 ramUsageFree);
2237 aCollector->registerBaseMetric (ramUsage);
2238
2239 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadUser, 0));
2240 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadUser,
2241 new pm::AggregateAvg()));
2242 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadUser,
2243 new pm::AggregateMin()));
2244 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadUser,
2245 new pm::AggregateMax()));
2246
2247 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadKernel, 0));
2248 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadKernel,
2249 new pm::AggregateAvg()));
2250 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadKernel,
2251 new pm::AggregateMin()));
2252 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadKernel,
2253 new pm::AggregateMax()));
2254
2255 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadIdle, 0));
2256 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadIdle,
2257 new pm::AggregateAvg()));
2258 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadIdle,
2259 new pm::AggregateMin()));
2260 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadIdle,
2261 new pm::AggregateMax()));
2262
2263 aCollector->registerMetric (new pm::Metric(cpuMhz, cpuMhzSM, 0));
2264 aCollector->registerMetric (new pm::Metric(cpuMhz, cpuMhzSM,
2265 new pm::AggregateAvg()));
2266 aCollector->registerMetric (new pm::Metric(cpuMhz, cpuMhzSM,
2267 new pm::AggregateMin()));
2268 aCollector->registerMetric (new pm::Metric(cpuMhz, cpuMhzSM,
2269 new pm::AggregateMax()));
2270
2271 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageTotal, 0));
2272 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageTotal,
2273 new pm::AggregateAvg()));
2274 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageTotal,
2275 new pm::AggregateMin()));
2276 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageTotal,
2277 new pm::AggregateMax()));
2278
2279 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageUsed, 0));
2280 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageUsed,
2281 new pm::AggregateAvg()));
2282 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageUsed,
2283 new pm::AggregateMin()));
2284 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageUsed,
2285 new pm::AggregateMax()));
2286
2287 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageFree, 0));
2288 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageFree,
2289 new pm::AggregateAvg()));
2290 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageFree,
2291 new pm::AggregateMin()));
2292 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageFree,
2293 new pm::AggregateMax()));
2294};
2295
2296void Host::unregisterMetrics (PerformanceCollector *aCollector)
2297{
2298 aCollector->unregisterMetricsFor (this);
2299 aCollector->unregisterBaseMetricsFor (this);
2300};
2301#endif /* VBOX_WITH_RESOURCE_USAGE_API */
2302
2303STDMETHODIMP Host::FindHostDVDDrive(IN_BSTR aName, IHostDVDDrive **aDrive)
2304{
2305 CheckComArgNotNull(aName);
2306 CheckComArgOutPointerValid(aDrive);
2307
2308 *aDrive = NULL;
2309
2310 SafeIfaceArray <IHostDVDDrive> drivevec;
2311 HRESULT rc = COMGETTER(DVDDrives) (ComSafeArrayAsOutParam(drivevec));
2312 CheckComRCReturnRC (rc);
2313
2314 for (size_t i = 0; i < drivevec.size(); ++i)
2315 {
2316 Bstr name;
2317 rc = drivevec[i]->COMGETTER(Name) (name.asOutParam());
2318 CheckComRCReturnRC (rc);
2319 if (name == aName)
2320 {
2321 ComObjPtr<HostDVDDrive> found;
2322 found.createObject();
2323 Bstr udi, description;
2324 rc = drivevec[i]->COMGETTER(Udi) (udi.asOutParam());
2325 CheckComRCReturnRC (rc);
2326 rc = drivevec[i]->COMGETTER(Description) (description.asOutParam());
2327 CheckComRCReturnRC (rc);
2328 found->init(name, udi, description);
2329 return found.queryInterfaceTo(aDrive);
2330 }
2331 }
2332
2333 return setError (VBOX_E_OBJECT_NOT_FOUND, HostDVDDrive::tr (
2334 "The host DVD drive named '%ls' could not be found"), aName);
2335}
2336
2337STDMETHODIMP Host::FindHostFloppyDrive(IN_BSTR aName, IHostFloppyDrive **aDrive)
2338{
2339 CheckComArgNotNull(aName);
2340 CheckComArgOutPointerValid(aDrive);
2341
2342 *aDrive = NULL;
2343
2344 SafeIfaceArray <IHostFloppyDrive> drivevec;
2345 HRESULT rc = COMGETTER(FloppyDrives) (ComSafeArrayAsOutParam(drivevec));
2346 CheckComRCReturnRC (rc);
2347
2348 for (size_t i = 0; i < drivevec.size(); ++i)
2349 {
2350 Bstr name;
2351 rc = drivevec[i]->COMGETTER(Name) (name.asOutParam());
2352 CheckComRCReturnRC (rc);
2353 if (name == aName)
2354 {
2355 ComObjPtr<HostFloppyDrive> found;
2356 found.createObject();
2357 Bstr udi, description;
2358 rc = drivevec[i]->COMGETTER(Udi) (udi.asOutParam());
2359 CheckComRCReturnRC (rc);
2360 rc = drivevec[i]->COMGETTER(Description) (description.asOutParam());
2361 CheckComRCReturnRC (rc);
2362 found->init(name, udi, description);
2363 return found.queryInterfaceTo(aDrive);
2364 }
2365 }
2366
2367 return setError (VBOX_E_OBJECT_NOT_FOUND, HostFloppyDrive::tr (
2368 "The host floppy drive named '%ls' could not be found"), aName);
2369}
2370
2371STDMETHODIMP Host::FindHostNetworkInterfaceByName(IN_BSTR name, IHostNetworkInterface **networkInterface)
2372{
2373#ifndef VBOX_WITH_HOSTNETIF_API
2374 return E_NOTIMPL;
2375#else
2376 if (!name)
2377 return E_INVALIDARG;
2378 if (!networkInterface)
2379 return E_POINTER;
2380
2381 *networkInterface = NULL;
2382 ComObjPtr <HostNetworkInterface> found;
2383 std::list <ComObjPtr <HostNetworkInterface> > list;
2384 int rc = NetIfList(list);
2385 if (RT_FAILURE(rc))
2386 {
2387 Log(("Failed to get host network interface list with rc=%Vrc\n", rc));
2388 return E_FAIL;
2389 }
2390 std::list <ComObjPtr <HostNetworkInterface> >::iterator it;
2391 for (it = list.begin(); it != list.end(); ++it)
2392 {
2393 Bstr n;
2394 (*it)->COMGETTER(Name) (n.asOutParam());
2395 if (n == name)
2396 found = *it;
2397 }
2398
2399 if (!found)
2400 return setError (E_INVALIDARG, HostNetworkInterface::tr (
2401 "The host network interface with the given name could not be found"));
2402
2403 found->setVirtualBox(mParent);
2404
2405 return found.queryInterfaceTo (networkInterface);
2406#endif
2407}
2408
2409STDMETHODIMP Host::FindHostNetworkInterfaceById(IN_BSTR id, IHostNetworkInterface **networkInterface)
2410{
2411#ifndef VBOX_WITH_HOSTNETIF_API
2412 return E_NOTIMPL;
2413#else
2414 if (Guid(id).isEmpty())
2415 return E_INVALIDARG;
2416 if (!networkInterface)
2417 return E_POINTER;
2418
2419 *networkInterface = NULL;
2420 ComObjPtr <HostNetworkInterface> found;
2421 std::list <ComObjPtr <HostNetworkInterface> > list;
2422 int rc = NetIfList(list);
2423 if (RT_FAILURE(rc))
2424 {
2425 Log(("Failed to get host network interface list with rc=%Vrc\n", rc));
2426 return E_FAIL;
2427 }
2428 std::list <ComObjPtr <HostNetworkInterface> >::iterator it;
2429 for (it = list.begin(); it != list.end(); ++it)
2430 {
2431 Bstr g;
2432 (*it)->COMGETTER(Id) (g.asOutParam());
2433 if (g == id)
2434 found = *it;
2435 }
2436
2437 if (!found)
2438 return setError (E_INVALIDARG, HostNetworkInterface::tr (
2439 "The host network interface with the given GUID could not be found"));
2440
2441 found->setVirtualBox(mParent);
2442
2443 return found.queryInterfaceTo (networkInterface);
2444#endif
2445}
2446
2447STDMETHODIMP Host::FindHostNetworkInterfacesOfType(HostNetworkInterfaceType_T type, ComSafeArrayOut (IHostNetworkInterface *, aNetworkInterfaces))
2448{
2449 std::list <ComObjPtr <HostNetworkInterface> > allList;
2450 int rc = NetIfList(allList);
2451 if(RT_FAILURE(rc))
2452 return E_FAIL;
2453
2454 std::list <ComObjPtr <HostNetworkInterface> > resultList;
2455
2456 std::list <ComObjPtr <HostNetworkInterface> >::iterator it;
2457 for (it = allList.begin(); it != allList.end(); ++it)
2458 {
2459 HostNetworkInterfaceType_T t;
2460 HRESULT hr = (*it)->COMGETTER(InterfaceType)(&t);
2461 if(FAILED(hr))
2462 return hr;
2463
2464 if(t == type)
2465 {
2466 (*it)->setVirtualBox(mParent);
2467 resultList.push_back (*it);
2468 }
2469 }
2470
2471 SafeIfaceArray <IHostNetworkInterface> filteredNetworkInterfaces (resultList);
2472 filteredNetworkInterfaces.detachTo (ComSafeArrayOutArg (aNetworkInterfaces));
2473
2474 return S_OK;
2475}
2476
2477STDMETHODIMP Host::FindUSBDeviceByAddress (IN_BSTR aAddress, IHostUSBDevice **aDevice)
2478{
2479#ifdef VBOX_WITH_USB
2480 CheckComArgNotNull(aAddress);
2481 CheckComArgOutPointerValid(aDevice);
2482
2483 *aDevice = NULL;
2484
2485 SafeIfaceArray <IHostUSBDevice> devsvec;
2486 HRESULT rc = COMGETTER(USBDevices) (ComSafeArrayAsOutParam(devsvec));
2487 CheckComRCReturnRC (rc);
2488
2489 for (size_t i = 0; i < devsvec.size(); ++i)
2490 {
2491 Bstr address;
2492 rc = devsvec[i]->COMGETTER(Address) (address.asOutParam());
2493 CheckComRCReturnRC (rc);
2494 if (address == aAddress)
2495 {
2496 return ComObjPtr<IHostUSBDevice> (devsvec[i]).queryInterfaceTo (aDevice);
2497 }
2498 }
2499
2500 return setErrorNoLog (VBOX_E_OBJECT_NOT_FOUND, tr (
2501 "Could not find a USB device with address '%ls'"),
2502 aAddress);
2503
2504#else /* !VBOX_WITH_USB */
2505 NOREF(aAddress);
2506 NOREF(aDevice);
2507 return E_NOTIMPL;
2508#endif /* !VBOX_WITH_USB */
2509}
2510
2511STDMETHODIMP Host::FindUSBDeviceById (IN_BSTR aId, IHostUSBDevice **aDevice)
2512{
2513#ifdef VBOX_WITH_USB
2514 CheckComArgExpr(aId, Guid (aId).isEmpty() == false);
2515 CheckComArgOutPointerValid(aDevice);
2516
2517 *aDevice = NULL;
2518
2519 SafeIfaceArray <IHostUSBDevice> devsvec;
2520 HRESULT rc = COMGETTER(USBDevices) (ComSafeArrayAsOutParam(devsvec));
2521 CheckComRCReturnRC (rc);
2522
2523 for (size_t i = 0; i < devsvec.size(); ++i)
2524 {
2525 Bstr id;
2526 rc = devsvec[i]->COMGETTER(Id) (id.asOutParam());
2527 CheckComRCReturnRC (rc);
2528 if (id == aId)
2529 {
2530 return ComObjPtr<IHostUSBDevice> (devsvec[i]).queryInterfaceTo (aDevice);
2531 }
2532 }
2533
2534 return setErrorNoLog (VBOX_E_OBJECT_NOT_FOUND, tr (
2535 "Could not find a USB device with uuid {%RTuuid}"),
2536 Guid (aId).raw());
2537
2538#else /* !VBOX_WITH_USB */
2539 NOREF(aId);
2540 NOREF(aDevice);
2541 return E_NOTIMPL;
2542#endif /* !VBOX_WITH_USB */
2543}
2544
2545
2546/* 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