VirtualBox

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

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

HostDVD: Add basic support for FreeBSD. Passthrough is working quite well so far.

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