VirtualBox

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

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

fix OSE

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