VirtualBox

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

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

Main: opimization for r52856

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette