VirtualBox

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

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

API: weed out NULL strings, as many clients cannot use them

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

© 2023 Oracle
ContactPrivacy policyTerms of Use