VirtualBox

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

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

rename TAP to NetAdp, remove abandoned tap win code

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