VirtualBox

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

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

Main: back out r50147 until the locking is properly understood; will come back.

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