VirtualBox

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

Last change on this file since 14831 was 14820, checked in by vboxsync, 16 years ago

HostImpl.cpp: asm.h

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 123.5 KB
Line 
1/* $Id: HostImpl.cpp 14820 2008-11-30 00:24:50Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation: Host
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22#define __STDC_LIMIT_MACROS
23#define __STDC_CONSTANT_MACROS
24
25#ifdef RT_OS_LINUX
26# include <sys/types.h>
27# include <sys/stat.h>
28# include <unistd.h>
29# include <sys/ioctl.h>
30# include <fcntl.h>
31# include <mntent.h>
32/* bird: This is a hack to work around conflicts between these linux kernel headers
33 * and the GLIBC tcpip headers. They have different declarations of the 4
34 * standard byte order functions. */
35# define _LINUX_BYTEORDER_GENERIC_H
36# include <linux/cdrom.h>
37# ifdef VBOX_WITH_LIBHAL
38# include <libhal.h>
39/* These are defined by libhal.h and by VBox header files. */
40# undef TRUE
41# undef FALSE
42# endif
43# include <errno.h>
44# include <net/if.h>
45# include <net/if_arp.h>
46#endif /* RT_OS_LINUX */
47
48#ifdef RT_OS_SOLARIS
49# include <fcntl.h>
50# include <unistd.h>
51# include <stropts.h>
52# include <errno.h>
53# include <limits.h>
54# include <stdio.h>
55# ifdef VBOX_SOLARIS_NSL_RESOLVED
56# include <libdevinfo.h>
57# endif
58# include <net/if.h>
59# include <sys/socket.h>
60# include <sys/sockio.h>
61# include <net/if_arp.h>
62# include <net/if.h>
63# include <sys/types.h>
64# include <sys/stat.h>
65# include <sys/cdio.h>
66# include <sys/dkio.h>
67# include <sys/mnttab.h>
68# include <sys/mntent.h>
69/* Dynamic loading of libhal on Solaris hosts */
70# ifdef VBOX_USE_LIBHAL
71# include "vbox-libhal.h"
72extern "C" char *getfullrawname(char *);
73# endif
74# include "solaris/DynLoadLibSolaris.h"
75#endif /* RT_OS_SOLARIS */
76
77#ifdef RT_OS_WINDOWS
78# define _WIN32_DCOM
79# include <windows.h>
80# include <shellapi.h>
81# define INITGUID
82# include <guiddef.h>
83# include <devguid.h>
84# include <objbase.h>
85# include <setupapi.h>
86# include <shlobj.h>
87# include <cfgmgr32.h>
88
89#endif /* RT_OS_WINDOWS */
90
91
92#include "HostImpl.h"
93#include "HostDVDDriveImpl.h"
94#include "HostFloppyDriveImpl.h"
95#include "HostNetworkInterfaceImpl.h"
96#ifdef VBOX_WITH_USB
97# include "HostUSBDeviceImpl.h"
98# include "USBDeviceFilterImpl.h"
99# include "USBProxyService.h"
100#endif
101#include "VirtualBoxImpl.h"
102#include "MachineImpl.h"
103#include "Logging.h"
104
105#ifdef RT_OS_DARWIN
106# include "darwin/iokit.h"
107#endif
108
109
110#include <VBox/usb.h>
111#include <VBox/x86.h>
112#include <VBox/err.h>
113#include <iprt/asm.h>
114#include <iprt/string.h>
115#include <iprt/mp.h>
116#include <iprt/time.h>
117#include <iprt/param.h>
118#include <iprt/env.h>
119#ifdef RT_OS_SOLARIS
120# include <iprt/path.h>
121# include <iprt/ctype.h>
122#endif
123
124#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
125# include <VBox/WinNetConfig.h>
126#endif /* #if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT) */
127
128#include <stdio.h>
129
130#include <algorithm>
131
132
133
134// constructor / destructor
135/////////////////////////////////////////////////////////////////////////////
136
137HRESULT Host::FinalConstruct()
138{
139 return S_OK;
140}
141
142void Host::FinalRelease()
143{
144 if (isReady())
145 uninit();
146}
147
148// public initializer/uninitializer for internal purposes only
149/////////////////////////////////////////////////////////////////////////////
150
151/**
152 * Initializes the host object.
153 *
154 * @param aParent VirtualBox parent object.
155 */
156HRESULT Host::init (VirtualBox *aParent)
157{
158 LogFlowThisFunc (("isReady=%d\n", isReady()));
159
160 ComAssertRet (aParent, E_INVALIDARG);
161
162 AutoWriteLock alock (this);
163 ComAssertRet (!isReady(), E_FAIL);
164
165 mParent = aParent;
166
167#ifdef VBOX_WITH_USB
168 /*
169 * Create and initialize the USB Proxy Service.
170 */
171# if defined (RT_OS_DARWIN)
172 mUSBProxyService = new USBProxyServiceDarwin (this);
173# elif defined (RT_OS_LINUX)
174 mUSBProxyService = new USBProxyServiceLinux (this);
175# elif defined (RT_OS_OS2)
176 mUSBProxyService = new USBProxyServiceOs2 (this);
177# elif defined (RT_OS_SOLARIS)
178 mUSBProxyService = new USBProxyServiceSolaris (this);
179# elif defined (RT_OS_WINDOWS)
180 mUSBProxyService = new USBProxyServiceWindows (this);
181# else
182 mUSBProxyService = new USBProxyService (this);
183# endif
184 HRESULT hrc = mUSBProxyService->init();
185 AssertComRCReturn(hrc, hrc);
186#endif /* VBOX_WITH_USB */
187
188#ifdef VBOX_WITH_RESOURCE_USAGE_API
189 registerMetrics (aParent->performanceCollector());
190#endif /* VBOX_WITH_RESOURCE_USAGE_API */
191
192#if defined (RT_OS_WINDOWS)
193 mHostPowerService = new HostPowerServiceWin (mParent);
194#elif defined (RT_OS_DARWIN)
195 mHostPowerService = new HostPowerServiceDarwin (mParent);
196#else
197 mHostPowerService = new HostPowerService (mParent);
198#endif
199
200 /* Cache the features reported by GetProcessorFeature. */
201 fVTxAMDVSupported = false;
202 fLongModeSupported = false;
203 fPAESupported = false;
204
205 if (ASMHasCpuId())
206 {
207 uint32_t u32FeaturesECX;
208 uint32_t u32Dummy;
209 uint32_t u32FeaturesEDX;
210 uint32_t u32VendorEBX, u32VendorECX, u32VendorEDX, u32AMDFeatureEDX, u32AMDFeatureECX;
211
212 ASMCpuId (0, &u32Dummy, &u32VendorEBX, &u32VendorECX, &u32VendorEDX);
213 ASMCpuId (1, &u32Dummy, &u32Dummy, &u32FeaturesECX, &u32FeaturesEDX);
214 /* Query AMD features. */
215 ASMCpuId (0x80000001, &u32Dummy, &u32Dummy, &u32AMDFeatureECX, &u32AMDFeatureEDX);
216
217 fLongModeSupported = !!(u32AMDFeatureEDX & X86_CPUID_AMD_FEATURE_EDX_LONG_MODE);
218 fPAESupported = !!(u32FeaturesEDX & X86_CPUID_FEATURE_EDX_PAE);
219
220 if ( u32VendorEBX == X86_CPUID_VENDOR_INTEL_EBX
221 && u32VendorECX == X86_CPUID_VENDOR_INTEL_ECX
222 && u32VendorEDX == X86_CPUID_VENDOR_INTEL_EDX
223 )
224 {
225 if ( (u32FeaturesECX & X86_CPUID_FEATURE_ECX_VMX)
226 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR)
227 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR)
228 )
229 fVTxAMDVSupported = true;
230 }
231 else
232 if ( u32VendorEBX == X86_CPUID_VENDOR_AMD_EBX
233 && u32VendorECX == X86_CPUID_VENDOR_AMD_ECX
234 && u32VendorEDX == X86_CPUID_VENDOR_AMD_EDX
235 )
236 {
237 if ( (u32AMDFeatureECX & X86_CPUID_AMD_FEATURE_ECX_SVM)
238 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR)
239 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR)
240 )
241 fVTxAMDVSupported = true;
242 }
243 }
244
245 setReady(true);
246 return S_OK;
247}
248
249/**
250 * Uninitializes the host object and sets the ready flag to FALSE.
251 * Called either from FinalRelease() or by the parent when it gets destroyed.
252 */
253void Host::uninit()
254{
255 LogFlowThisFunc (("isReady=%d\n", isReady()));
256
257 AssertReturn (isReady(), (void) 0);
258
259#ifdef VBOX_WITH_RESOURCE_USAGE_API
260 unregisterMetrics (mParent->performanceCollector());
261#endif /* VBOX_WITH_RESOURCE_USAGE_API */
262
263#ifdef VBOX_WITH_USB
264 /* wait for USB proxy service to terminate before we uninit all USB
265 * devices */
266 LogFlowThisFunc (("Stopping USB proxy service...\n"));
267 delete mUSBProxyService;
268 mUSBProxyService = NULL;
269 LogFlowThisFunc (("Done stopping USB proxy service.\n"));
270#endif
271
272 delete mHostPowerService;
273
274 /* uninit all USB device filters still referenced by clients */
275 uninitDependentChildren();
276
277#ifdef VBOX_WITH_USB
278 mUSBDeviceFilters.clear();
279#endif
280
281 setReady (FALSE);
282}
283
284// IHost properties
285/////////////////////////////////////////////////////////////////////////////
286
287/**
288 * Returns a list of host DVD drives.
289 *
290 * @returns COM status code
291 * @param drives address of result pointer
292 */
293STDMETHODIMP Host::COMGETTER(DVDDrives) (IHostDVDDriveCollection **drives)
294{
295 if (!drives)
296 return E_POINTER;
297 AutoWriteLock alock (this);
298 CHECK_READY();
299 std::list <ComObjPtr <HostDVDDrive> > list;
300
301#if defined(RT_OS_WINDOWS)
302 int sz = GetLogicalDriveStrings(0, NULL);
303 TCHAR *hostDrives = new TCHAR[sz+1];
304 GetLogicalDriveStrings(sz, hostDrives);
305 wchar_t driveName[3] = { '?', ':', '\0' };
306 TCHAR *p = hostDrives;
307 do
308 {
309 if (GetDriveType(p) == DRIVE_CDROM)
310 {
311 driveName[0] = *p;
312 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
313 hostDVDDriveObj.createObject();
314 hostDVDDriveObj->init (Bstr (driveName));
315 list.push_back (hostDVDDriveObj);
316 }
317 p += _tcslen(p) + 1;
318 }
319 while (*p);
320 delete[] hostDrives;
321
322#elif defined(RT_OS_SOLARIS)
323# ifdef VBOX_USE_LIBHAL
324 if (!getDVDInfoFromHal(list))
325# endif
326 // Not all Solaris versions ship with libhal.
327 // So use a fallback approach similar to Linux.
328 {
329 if (RTEnvGet("VBOX_CDROM"))
330 {
331 char *cdromEnv = strdup(RTEnvGet("VBOX_CDROM"));
332 char *cdromDrive;
333 cdromDrive = strtok(cdromEnv, ":"); /** @todo use strtok_r. */
334 while (cdromDrive)
335 {
336 if (validateDevice(cdromDrive, true))
337 {
338 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
339 hostDVDDriveObj.createObject();
340 hostDVDDriveObj->init (Bstr (cdromDrive));
341 list.push_back (hostDVDDriveObj);
342 }
343 cdromDrive = strtok(NULL, ":");
344 }
345 free(cdromEnv);
346 }
347 else
348 {
349 // this might work on Solaris version older than Nevada.
350 if (validateDevice("/cdrom/cdrom0", true))
351 {
352 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
353 hostDVDDriveObj.createObject();
354 hostDVDDriveObj->init (Bstr ("cdrom/cdrom0"));
355 list.push_back (hostDVDDriveObj);
356 }
357
358 // check the mounted drives
359 parseMountTable(MNTTAB, list);
360 }
361 }
362
363#elif defined(RT_OS_LINUX)
364#ifdef VBOX_WITH_LIBHAL
365 if (!getDVDInfoFromHal(list)) /* Playing with #defines in this way is nasty, I know. */
366#endif /* VBOX_WITH_LIBHAL defined */
367 // On Linux without hal, the situation is much more complex. We will take a
368 // heuristical approach and also allow the user to specify a list of host
369 // CDROMs using an environment variable.
370 // The general strategy is to try some known device names and see of they
371 // exist. At last, we'll enumerate the /etc/fstab file (luckily there's an
372 // API to parse it) for CDROM devices. Ok, let's start!
373
374 {
375 if (RTEnvGet("VBOX_CDROM"))
376 {
377 char *cdromEnv = strdupa(RTEnvGet("VBOX_CDROM"));
378 char *cdromDrive;
379 cdromDrive = strtok(cdromEnv, ":"); /** @todo use strtok_r */
380 while (cdromDrive)
381 {
382 if (validateDevice(cdromDrive, true))
383 {
384 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
385 hostDVDDriveObj.createObject();
386 hostDVDDriveObj->init (Bstr (cdromDrive));
387 list.push_back (hostDVDDriveObj);
388 }
389 cdromDrive = strtok(NULL, ":");
390 }
391 }
392 else
393 {
394 // this is a good guess usually
395 if (validateDevice("/dev/cdrom", true))
396 {
397 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
398 hostDVDDriveObj.createObject();
399 hostDVDDriveObj->init (Bstr ("/dev/cdrom"));
400 list.push_back (hostDVDDriveObj);
401 }
402
403 // check the mounted drives
404 parseMountTable((char*)"/etc/mtab", list);
405
406 // check the drives that can be mounted
407 parseMountTable((char*)"/etc/fstab", list);
408 }
409 }
410#elif defined(RT_OS_DARWIN)
411 PDARWINDVD cur = DarwinGetDVDDrives();
412 while (cur)
413 {
414 ComObjPtr<HostDVDDrive> hostDVDDriveObj;
415 hostDVDDriveObj.createObject();
416 hostDVDDriveObj->init(Bstr(cur->szName));
417 list.push_back(hostDVDDriveObj);
418
419 /* next */
420 void *freeMe = cur;
421 cur = cur->pNext;
422 RTMemFree(freeMe);
423 }
424
425#else
426 /* PORTME */
427#endif
428
429 ComObjPtr<HostDVDDriveCollection> collection;
430 collection.createObject();
431 collection->init (list);
432 collection.queryInterfaceTo(drives);
433 return S_OK;
434}
435
436/**
437 * Returns a list of host floppy drives.
438 *
439 * @returns COM status code
440 * @param drives address of result pointer
441 */
442STDMETHODIMP Host::COMGETTER(FloppyDrives) (IHostFloppyDriveCollection **drives)
443{
444 if (!drives)
445 return E_POINTER;
446 AutoWriteLock alock (this);
447 CHECK_READY();
448
449 std::list <ComObjPtr <HostFloppyDrive> > list;
450
451#ifdef RT_OS_WINDOWS
452 int sz = GetLogicalDriveStrings(0, NULL);
453 TCHAR *hostDrives = new TCHAR[sz+1];
454 GetLogicalDriveStrings(sz, hostDrives);
455 wchar_t driveName[3] = { '?', ':', '\0' };
456 TCHAR *p = hostDrives;
457 do
458 {
459 if (GetDriveType(p) == DRIVE_REMOVABLE)
460 {
461 driveName[0] = *p;
462 ComObjPtr <HostFloppyDrive> hostFloppyDriveObj;
463 hostFloppyDriveObj.createObject();
464 hostFloppyDriveObj->init (Bstr (driveName));
465 list.push_back (hostFloppyDriveObj);
466 }
467 p += _tcslen(p) + 1;
468 }
469 while (*p);
470 delete[] hostDrives;
471#elif defined(RT_OS_LINUX)
472#ifdef VBOX_WITH_LIBHAL
473 if (!getFloppyInfoFromHal(list)) /* Playing with #defines in this way is nasty, I know. */
474#endif /* VBOX_WITH_LIBHAL defined */
475 // As with the CDROMs, on Linux we have to take a multi-level approach
476 // involving parsing the mount tables. As this is not bulletproof, we'll
477 // give the user the chance to override the detection by an environment
478 // variable and skip the detection.
479
480 {
481 if (RTEnvGet("VBOX_FLOPPY"))
482 {
483 char *floppyEnv = strdupa(RTEnvGet("VBOX_FLOPPY"));
484 char *floppyDrive;
485 floppyDrive = strtok(floppyEnv, ":");
486 while (floppyDrive)
487 {
488 // check if this is an acceptable device
489 if (validateDevice(floppyDrive, false))
490 {
491 ComObjPtr <HostFloppyDrive> hostFloppyDriveObj;
492 hostFloppyDriveObj.createObject();
493 hostFloppyDriveObj->init (Bstr (floppyDrive));
494 list.push_back (hostFloppyDriveObj);
495 }
496 floppyDrive = strtok(NULL, ":");
497 }
498 }
499 else
500 {
501 // we assume that a floppy is always /dev/fd[x] with x from 0 to 7
502 char devName[10];
503 for (int i = 0; i <= 7; i++)
504 {
505 sprintf(devName, "/dev/fd%d", i);
506 if (validateDevice(devName, false))
507 {
508 ComObjPtr <HostFloppyDrive> hostFloppyDriveObj;
509 hostFloppyDriveObj.createObject();
510 hostFloppyDriveObj->init (Bstr (devName));
511 list.push_back (hostFloppyDriveObj);
512 }
513 }
514 }
515 }
516#else
517 /* PORTME */
518#endif
519
520 ComObjPtr<HostFloppyDriveCollection> collection;
521 collection.createObject();
522 collection->init (list);
523 collection.queryInterfaceTo(drives);
524 return S_OK;
525}
526
527#ifdef RT_OS_WINDOWS
528/**
529 * Windows helper function for Host::COMGETTER(NetworkInterfaces).
530 *
531 * @returns true / false.
532 *
533 * @param guid The GUID.
534 */
535static bool IsTAPDevice(const char *guid)
536{
537 HKEY hNetcard;
538 LONG status;
539 DWORD len;
540 int i = 0;
541 bool ret = false;
542
543 status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}", 0, KEY_READ, &hNetcard);
544 if (status != ERROR_SUCCESS)
545 return false;
546
547 for (;;)
548 {
549 char szEnumName[256];
550 char szNetCfgInstanceId[256];
551 DWORD dwKeyType;
552 HKEY hNetCardGUID;
553
554 len = sizeof(szEnumName);
555 status = RegEnumKeyExA(hNetcard, i, szEnumName, &len, NULL, NULL, NULL, NULL);
556 if (status != ERROR_SUCCESS)
557 break;
558
559 status = RegOpenKeyExA(hNetcard, szEnumName, 0, KEY_READ, &hNetCardGUID);
560 if (status == ERROR_SUCCESS)
561 {
562 len = sizeof(szNetCfgInstanceId);
563 status = RegQueryValueExA(hNetCardGUID, "NetCfgInstanceId", NULL, &dwKeyType, (LPBYTE)szNetCfgInstanceId, &len);
564 if (status == ERROR_SUCCESS && dwKeyType == REG_SZ)
565 {
566 char szNetProductName[256];
567 char szNetProviderName[256];
568
569 szNetProductName[0] = 0;
570 len = sizeof(szNetProductName);
571 status = RegQueryValueExA(hNetCardGUID, "ProductName", NULL, &dwKeyType, (LPBYTE)szNetProductName, &len);
572
573 szNetProviderName[0] = 0;
574 len = sizeof(szNetProviderName);
575 status = RegQueryValueExA(hNetCardGUID, "ProviderName", NULL, &dwKeyType, (LPBYTE)szNetProviderName, &len);
576
577 if ( !strcmp(szNetCfgInstanceId, guid)
578 && !strcmp(szNetProductName, "VirtualBox TAP Adapter")
579 && ( !strcmp(szNetProviderName, "innotek GmbH")
580 || !strcmp(szNetProviderName, "Sun Microsystems, Inc.")))
581 {
582 ret = true;
583 RegCloseKey(hNetCardGUID);
584 break;
585 }
586 }
587 RegCloseKey(hNetCardGUID);
588 }
589 ++i;
590 }
591
592 RegCloseKey(hNetcard);
593 return ret;
594}
595#endif /* RT_OS_WINDOWS */
596
597#ifdef RT_OS_SOLARIS
598static void vboxSolarisAddHostIface(char *pszIface, int Instance, PCRTMAC pMac, void *pvHostNetworkInterfaceList)
599{
600 std::list<ComObjPtr <HostNetworkInterface> > *pList = (std::list<ComObjPtr <HostNetworkInterface> > *)pvHostNetworkInterfaceList;
601 Assert(pList);
602
603 typedef std::map <std::string, std::string> NICMap;
604 typedef std::pair <std::string, std::string> NICPair;
605 static NICMap SolarisNICMap;
606 if (SolarisNICMap.empty())
607 {
608 SolarisNICMap.insert(NICPair("afe", "ADMtek Centaur/Comet Fast Ethernet"));
609 SolarisNICMap.insert(NICPair("aggr", "Link Aggregation Interface"));
610 SolarisNICMap.insert(NICPair("bge", "Broadcom BCM57xx Gigabit Ethernet"));
611 SolarisNICMap.insert(NICPair("ce", "Cassini Gigabit Ethernet"));
612 SolarisNICMap.insert(NICPair("chxge", "Chelsio Ethernet"));
613 SolarisNICMap.insert(NICPair("dmfe", "Davicom Fast Ethernet"));
614 SolarisNICMap.insert(NICPair("dnet", "DEC 21040/41 21140 Ethernet"));
615 SolarisNICMap.insert(NICPair("e1000", "Intel PRO/1000 Gigabit Ethernet"));
616 SolarisNICMap.insert(NICPair("e1000g", "Intel PRO/1000 Gigabit Ethernet"));
617 SolarisNICMap.insert(NICPair("elx", "3COM EtherLink III Ethernet"));
618 SolarisNICMap.insert(NICPair("elxl", "3COM Ethernet"));
619 SolarisNICMap.insert(NICPair("eri", "eri Fast Ethernet"));
620 SolarisNICMap.insert(NICPair("ge", "GEM Gigabit Ethernet"));
621 SolarisNICMap.insert(NICPair("hme", "SUNW,hme Fast-Ethernet"));
622 SolarisNICMap.insert(NICPair("ipge", "PCI-E Gigabit Ethernet"));
623 SolarisNICMap.insert(NICPair("iprb", "Intel 82557/58/59 Ethernet"));
624 SolarisNICMap.insert(NICPair("mxfe", "Macronix 98715 Fast Ethernet"));
625 SolarisNICMap.insert(NICPair("nge", "Nvidia Gigabit Ethernet"));
626 SolarisNICMap.insert(NICPair("pcelx", "3COM EtherLink III PCMCIA Ethernet"));
627 SolarisNICMap.insert(NICPair("pcn", "AMD PCnet Ethernet"));
628 SolarisNICMap.insert(NICPair("qfe", "SUNW,qfe Quad Fast-Ethernet"));
629 SolarisNICMap.insert(NICPair("rge", "Realtek Gigabit Ethernet"));
630 SolarisNICMap.insert(NICPair("rtls", "Realtek 8139 Fast Ethernet"));
631 SolarisNICMap.insert(NICPair("skge", "SksKonnect Gigabit Ethernet"));
632 SolarisNICMap.insert(NICPair("spwr", "SMC EtherPower II 10/100 (9432) Ethernet"));
633 SolarisNICMap.insert(NICPair("vnic", "Virtual Network Interface Ethernet"));
634 SolarisNICMap.insert(NICPair("xge", "Neterior Xframe Gigabit Ethernet"));
635 SolarisNICMap.insert(NICPair("xge", "Neterior Xframe 10Gigabit Ethernet"));
636 }
637
638 /*
639 * Try picking up description from our NIC map.
640 */
641 char szNICInstance[128];
642 RTStrPrintf(szNICInstance, sizeof(szNICInstance), "%s%d", pszIface, Instance);
643 char szNICDesc[256];
644 std::string Description = SolarisNICMap[pszIface];
645 if (Description != "")
646 RTStrPrintf(szNICDesc, sizeof(szNICDesc), "%s - %s", szNICInstance, Description.c_str());
647 else
648 RTStrPrintf(szNICDesc, sizeof(szNICDesc), "%s - Ethernet", szNICInstance);
649
650 /*
651 * Construct UUID with interface name and the MAC address if available.
652 */
653 RTUUID Uuid;
654 RTUuidClear(&Uuid);
655 memcpy(&Uuid, szNICInstance, RT_MIN(strlen(szNICInstance), sizeof(Uuid)));
656 Uuid.Gen.u8ClockSeqHiAndReserved = (Uuid.Gen.u8ClockSeqHiAndReserved & 0x3f) | 0x80;
657 Uuid.Gen.u16TimeHiAndVersion = (Uuid.Gen.u16TimeHiAndVersion & 0x0fff) | 0x4000;
658 if (pMac)
659 {
660 Uuid.Gen.au8Node[0] = pMac->au8[0];
661 Uuid.Gen.au8Node[1] = pMac->au8[1];
662 Uuid.Gen.au8Node[2] = pMac->au8[2];
663 Uuid.Gen.au8Node[3] = pMac->au8[3];
664 Uuid.Gen.au8Node[4] = pMac->au8[4];
665 Uuid.Gen.au8Node[5] = pMac->au8[5];
666 }
667
668 ComObjPtr<HostNetworkInterface> IfObj;
669 IfObj.createObject();
670 if (SUCCEEDED(IfObj->init(Bstr(szNICDesc), Guid(Uuid))))
671 pList->push_back(IfObj);
672}
673
674static boolean_t vboxSolarisAddLinkHostIface(const char *pszIface, void *pvHostNetworkInterfaceList)
675{
676 /*
677 * Clip off the zone instance number from the interface name (if any).
678 */
679 char szIfaceName[128];
680 strcpy(szIfaceName, pszIface);
681 char *pszColon = (char *)memchr(szIfaceName, ':', sizeof(szIfaceName));
682 if (pszColon)
683 *pszColon = '\0';
684
685 /*
686 * Get the instance number from the interface name, then clip it off.
687 */
688 int cbInstance = 0;
689 int cbIface = strlen(szIfaceName);
690 const char *pszEnd = pszIface + cbIface - 1;
691 for (int i = 0; i < cbIface - 1; i++)
692 {
693 if (!RT_C_IS_DIGIT(*pszEnd))
694 break;
695 cbInstance++;
696 pszEnd--;
697 }
698
699 int Instance = atoi(pszEnd + 1);
700 strncpy(szIfaceName, pszIface, cbIface - cbInstance);
701 szIfaceName[cbIface - cbInstance] = '\0';
702
703 /*
704 * Add the interface.
705 */
706 vboxSolarisAddHostIface(szIfaceName, Instance, NULL, pvHostNetworkInterfaceList);
707
708 /*
709 * Continue walking...
710 */
711 return _B_FALSE;
712}
713
714static bool vboxSolarisSortNICList(const ComObjPtr <HostNetworkInterface> Iface1, const ComObjPtr <HostNetworkInterface> Iface2)
715{
716 Bstr Iface1Str;
717 (*Iface1).COMGETTER(Name) (Iface1Str.asOutParam());
718
719 Bstr Iface2Str;
720 (*Iface2).COMGETTER(Name) (Iface2Str.asOutParam());
721
722 return Iface1Str < Iface2Str;
723}
724
725static bool vboxSolarisSameNIC(const ComObjPtr <HostNetworkInterface> Iface1, const ComObjPtr <HostNetworkInterface> Iface2)
726{
727 Bstr Iface1Str;
728 (*Iface1).COMGETTER(Name) (Iface1Str.asOutParam());
729
730 Bstr Iface2Str;
731 (*Iface2).COMGETTER(Name) (Iface2Str.asOutParam());
732
733 return (Iface1Str == Iface2Str);
734}
735
736# ifdef VBOX_SOLARIS_NSL_RESOLVED
737static int vboxSolarisAddPhysHostIface(di_node_t Node, di_minor_t Minor, void *pvHostNetworkInterfaceList)
738{
739 /*
740 * Skip aggregations.
741 */
742 if (!strcmp(di_driver_name(Node), "aggr"))
743 return DI_WALK_CONTINUE;
744
745 /*
746 * Skip softmacs.
747 */
748 if (!strcmp(di_driver_name(Node), "softmac"))
749 return DI_WALK_CONTINUE;
750
751 vboxSolarisAddHostIface(di_driver_name(Node), di_instance(Node), NULL, pvHostNetworkInterfaceList);
752 return DI_WALK_CONTINUE;
753}
754# endif /* VBOX_SOLARIS_NSL_RESOLVED */
755
756#endif
757
758#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
759# define VBOX_APP_NAME L"VirtualBox"
760
761static int vboxNetWinAddComponent(std::list <ComObjPtr <HostNetworkInterface> > * pPist, INetCfgComponent * pncc)
762{
763 LPWSTR lpszName;
764 GUID IfGuid;
765 HRESULT hr;
766 int rc = VERR_GENERAL_FAILURE;
767
768 hr = pncc->GetDisplayName( &lpszName );
769 Assert(hr == S_OK);
770 if(hr == S_OK)
771 {
772 size_t cUnicodeName = wcslen(lpszName) + 1;
773 size_t uniLen = (cUnicodeName * 2 + sizeof (OLECHAR) - 1) / sizeof (OLECHAR);
774 Bstr name (uniLen + 1 /* extra zero */);
775 wcscpy((wchar_t *) name.mutableRaw(), lpszName);
776
777 hr = pncc->GetInstanceGuid(&IfGuid);
778 Assert(hr == S_OK);
779 if (hr == S_OK)
780 {
781 /* create a new object and add it to the list */
782 ComObjPtr <HostNetworkInterface> iface;
783 iface.createObject();
784 /* remove the curly bracket at the end */
785 if (SUCCEEDED (iface->init (name, Guid (IfGuid))))
786 {
787 pPist->push_back (iface);
788 rc = VINF_SUCCESS;
789 }
790 else
791 {
792 Assert(0);
793 }
794 }
795 CoTaskMemFree(lpszName);
796 }
797
798 return rc;
799}
800
801#endif /* #if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT) */
802
803/**
804 * Returns a list of host network interfaces.
805 *
806 * @returns COM status code
807 * @param drives address of result pointer
808 */
809STDMETHODIMP Host::COMGETTER(NetworkInterfaces) (IHostNetworkInterfaceCollection **networkInterfaces)
810{
811#if defined(RT_OS_WINDOWS) || defined(VBOX_WITH_NETFLT) /*|| defined(RT_OS_OS2)*/
812 if (!networkInterfaces)
813 return E_POINTER;
814 AutoWriteLock alock (this);
815 CHECK_READY();
816
817 std::list <ComObjPtr <HostNetworkInterface> > list;
818
819# if defined(RT_OS_DARWIN)
820 PDARWINETHERNIC pEtherNICs = DarwinGetEthernetControllers();
821 while (pEtherNICs)
822 {
823 ComObjPtr<HostNetworkInterface> IfObj;
824 IfObj.createObject();
825 if (SUCCEEDED(IfObj->init(Bstr(pEtherNICs->szName), Guid(pEtherNICs->Uuid))))
826 list.push_back(IfObj);
827
828 /* next, free current */
829 void *pvFree = pEtherNICs;
830 pEtherNICs = pEtherNICs->pNext;
831 RTMemFree(pvFree);
832 }
833
834# elif defined(RT_OS_SOLARIS)
835
836# ifdef VBOX_SOLARIS_NSL_RESOLVED
837
838 /*
839 * Use libdevinfo for determining all physical interfaces.
840 */
841 di_node_t Root;
842 Root = di_init("/", DINFOCACHE);
843 if (Root != DI_NODE_NIL)
844 {
845 di_walk_minor(Root, DDI_NT_NET, 0, &list, vboxSolarisAddPhysHostIface);
846 di_fini(Root);
847 }
848
849 /*
850 * Use libdlpi for determining all DLPI interfaces.
851 */
852 if (VBoxSolarisLibDlpiFound())
853 g_pfnLibDlpiWalk(vboxSolarisAddLinkHostIface, &list, 0);
854
855# endif /* VBOX_SOLARIS_NSL_RESOLVED */
856
857 /*
858 * This gets only the list of all plumbed logical interfaces.
859 * This is needed for zones which cannot access the device tree
860 * and in this case we just let them use the list of plumbed interfaces
861 * on the zone.
862 */
863 int Sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
864 if (Sock > 0)
865 {
866 struct lifnum IfNum;
867 memset(&IfNum, 0, sizeof(IfNum));
868 IfNum.lifn_family = AF_INET;
869 int rc = ioctl(Sock, SIOCGLIFNUM, &IfNum);
870 if (!rc)
871 {
872 struct lifreq Ifaces[24];
873 struct lifconf IfConfig;
874 memset(&IfConfig, 0, sizeof(IfConfig));
875 IfConfig.lifc_family = AF_INET;
876 IfConfig.lifc_len = sizeof(Ifaces);
877 IfConfig.lifc_buf = (caddr_t)&(Ifaces[0]);
878 rc = ioctl(Sock, SIOCGLIFCONF, &IfConfig);
879 if (!rc)
880 {
881 for (int i = 0; i < IfNum.lifn_count; i++)
882 {
883 /*
884 * Skip loopback interfaces.
885 */
886 if (!strncmp(Ifaces[i].lifr_name, "lo", 2))
887 continue;
888
889#if 0
890 rc = ioctl(Sock, SIOCGLIFADDR, &(Ifaces[i]));
891 if (!rc)
892 {
893 RTMAC Mac;
894 struct arpreq ArpReq;
895 memcpy(&ArpReq.arp_pa, &Ifaces[i].lifr_addr, sizeof(struct sockaddr_in));
896
897 /*
898 * We might fail if the interface has not been assigned an IP address.
899 * That doesn't matter; as long as it's plumbed we can pick it up.
900 * But, if it has not acquired an IP address we cannot obtain it's MAC
901 * address this way, so we just use all zeros there.
902 */
903 rc = ioctl(Sock, SIOCGARP, &ArpReq);
904 if (!rc)
905 memcpy(&Mac, ArpReq.arp_ha.sa_data, sizeof(RTMAC));
906 else
907 memset(&Mac, 0, sizeof(Mac));
908
909 char szNICDesc[LIFNAMSIZ + 256];
910 char *pszIface = Ifaces[i].lifr_name;
911 strcpy(szNICDesc, pszIface);
912
913 vboxSolarisAddLinkHostIface(pszIface, &list);
914 }
915#endif
916
917 char *pszIface = Ifaces[i].lifr_name;
918 vboxSolarisAddLinkHostIface(pszIface, &list);
919 }
920 }
921 }
922 close(Sock);
923 }
924
925 /*
926 * Weed out duplicates caused by dlpi_walk inconsistencies across Nevadas.
927 */
928 list.sort(vboxSolarisSortNICList);
929 list.unique(vboxSolarisSameNIC);
930
931# elif defined RT_OS_WINDOWS
932# ifndef VBOX_WITH_NETFLT
933 static const char *NetworkKey = "SYSTEM\\CurrentControlSet\\Control\\Network\\"
934 "{4D36E972-E325-11CE-BFC1-08002BE10318}";
935 HKEY hCtrlNet;
936 LONG status;
937 DWORD len;
938 status = RegOpenKeyExA (HKEY_LOCAL_MACHINE, NetworkKey, 0, KEY_READ, &hCtrlNet);
939 if (status != ERROR_SUCCESS)
940 return setError (E_FAIL, tr("Could not open registry key \"%s\""), NetworkKey);
941
942 for (int i = 0;; ++ i)
943 {
944 char szNetworkGUID [256];
945 HKEY hConnection;
946 char szNetworkConnection [256];
947
948 len = sizeof (szNetworkGUID);
949 status = RegEnumKeyExA (hCtrlNet, i, szNetworkGUID, &len, NULL, NULL, NULL, NULL);
950 if (status != ERROR_SUCCESS)
951 break;
952
953 if (!IsTAPDevice(szNetworkGUID))
954 continue;
955
956 RTStrPrintf (szNetworkConnection, sizeof (szNetworkConnection),
957 "%s\\Connection", szNetworkGUID);
958 status = RegOpenKeyExA (hCtrlNet, szNetworkConnection, 0, KEY_READ, &hConnection);
959 if (status == ERROR_SUCCESS)
960 {
961 DWORD dwKeyType;
962 status = RegQueryValueExW (hConnection, TEXT("Name"), NULL,
963 &dwKeyType, NULL, &len);
964 if (status == ERROR_SUCCESS && dwKeyType == REG_SZ)
965 {
966 size_t uniLen = (len + sizeof (OLECHAR) - 1) / sizeof (OLECHAR);
967 Bstr name (uniLen + 1 /* extra zero */);
968 status = RegQueryValueExW (hConnection, TEXT("Name"), NULL,
969 &dwKeyType, (LPBYTE) name.mutableRaw(), &len);
970 if (status == ERROR_SUCCESS)
971 {
972 RTLogPrintf("Connection name %ls\n", name.mutableRaw());
973 /* put a trailing zero, just in case (see MSDN) */
974 name.mutableRaw() [uniLen] = 0;
975 /* create a new object and add it to the list */
976 ComObjPtr <HostNetworkInterface> iface;
977 iface.createObject();
978 /* remove the curly bracket at the end */
979 szNetworkGUID [strlen(szNetworkGUID) - 1] = '\0';
980 if (SUCCEEDED (iface->init (name, Guid (szNetworkGUID + 1))))
981 list.push_back (iface);
982 }
983 }
984 RegCloseKey (hConnection);
985 }
986 }
987 RegCloseKey (hCtrlNet);
988# else /* # if defined VBOX_WITH_NETFLT */
989 INetCfg *pNc;
990 INetCfgComponent *pMpNcc;
991 INetCfgComponent *pTcpIpNcc;
992 LPWSTR lpszApp;
993 HRESULT hr;
994 IEnumNetCfgBindingPath *pEnumBp;
995 INetCfgBindingPath *pBp;
996 IEnumNetCfgBindingInterface *pEnumBi;
997 INetCfgBindingInterface *pBi;
998
999 /* we are using the INetCfg API for getting the list of miniports */
1000 hr = VBoxNetCfgWinQueryINetCfg( FALSE,
1001 VBOX_APP_NAME,
1002 &pNc,
1003 &lpszApp );
1004 Assert(hr == S_OK);
1005 if(hr == S_OK)
1006 {
1007#ifdef VBOX_NETFLT_ONDEMAND_BIND
1008 /* for the protocol-based approach for now we just get all miniports the MS_TCPIP protocol binds to */
1009 hr = pNc->FindComponent(L"MS_TCPIP", &pTcpIpNcc);
1010#else
1011 /* for the filter-based approach we get all miniports our filter (sun_VBoxNetFlt)is bound to */
1012 hr = pNc->FindComponent(L"sun_VBoxNetFlt", &pTcpIpNcc);
1013# ifndef VBOX_WITH_HARDENING
1014 if(hr != S_OK)
1015 {
1016 /* TODO: try to install the netflt from here */
1017 }
1018# endif
1019
1020#endif
1021
1022 if(hr == S_OK)
1023 {
1024 hr = VBoxNetCfgWinGetBindingPathEnum(pTcpIpNcc, EBP_BELOW, &pEnumBp);
1025 Assert(hr == S_OK);
1026 if ( hr == S_OK )
1027 {
1028 hr = VBoxNetCfgWinGetFirstBindingPath(pEnumBp, &pBp);
1029 Assert(hr == S_OK || hr == S_FALSE);
1030 while( hr == S_OK )
1031 {
1032 /* S_OK == enabled, S_FALSE == disabled */
1033 if(pBp->IsEnabled() == S_OK)
1034 {
1035 hr = VBoxNetCfgWinGetBindingInterfaceEnum(pBp, &pEnumBi);
1036 Assert(hr == S_OK);
1037 if ( hr == S_OK )
1038 {
1039 hr = VBoxNetCfgWinGetFirstBindingInterface(pEnumBi, &pBi);
1040 Assert(hr == S_OK);
1041 while(hr == S_OK)
1042 {
1043 hr = pBi->GetLowerComponent( &pMpNcc );
1044 Assert(hr == S_OK);
1045 if(hr == S_OK)
1046 {
1047 vboxNetWinAddComponent(&list, pMpNcc);
1048 VBoxNetCfgWinReleaseRef( pMpNcc );
1049 }
1050 VBoxNetCfgWinReleaseRef(pBi);
1051
1052 hr = VBoxNetCfgWinGetNextBindingInterface(pEnumBi, &pBi);
1053 }
1054 VBoxNetCfgWinReleaseRef(pEnumBi);
1055 }
1056 }
1057 VBoxNetCfgWinReleaseRef(pBp);
1058
1059 hr = VBoxNetCfgWinGetNextBindingPath(pEnumBp, &pBp);
1060 }
1061 VBoxNetCfgWinReleaseRef(pEnumBp);
1062 }
1063 VBoxNetCfgWinReleaseRef(pTcpIpNcc);
1064 }
1065 else
1066 {
1067 LogRel(("failed to get the sun_VBoxNetFlt component, error (0x%x)", hr));
1068 }
1069
1070 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE);
1071 }
1072# endif /* # if defined VBOX_WITH_NETFLT */
1073
1074
1075# elif defined RT_OS_LINUX
1076 int sock = socket(AF_INET, SOCK_DGRAM, 0);
1077 if (sock >= 0)
1078 {
1079 char pBuffer[2048];
1080 struct ifconf ifConf;
1081 ifConf.ifc_len = sizeof(pBuffer);
1082 ifConf.ifc_buf = pBuffer;
1083 if (ioctl(sock, SIOCGIFCONF, &ifConf) >= 0)
1084 {
1085 for (struct ifreq *pReq = ifConf.ifc_req; (char*)pReq < pBuffer + ifConf.ifc_len; pReq++)
1086 {
1087 if (ioctl(sock, SIOCGIFHWADDR, pReq) >= 0)
1088 {
1089 if (pReq->ifr_hwaddr.sa_family == ARPHRD_ETHER)
1090 {
1091 RTUUID uuid;
1092 Assert(sizeof(uuid) <= sizeof(*pReq));
1093 memcpy(&uuid, pReq, sizeof(uuid));
1094
1095 ComObjPtr<HostNetworkInterface> IfObj;
1096 IfObj.createObject();
1097 if (SUCCEEDED(IfObj->init(Bstr(pReq->ifr_name), Guid(uuid))))
1098 list.push_back(IfObj);
1099 }
1100 }
1101 }
1102 }
1103 close(sock);
1104 }
1105# endif /* RT_OS_LINUX */
1106
1107 ComObjPtr <HostNetworkInterfaceCollection> collection;
1108 collection.createObject();
1109 collection->init (list);
1110 collection.queryInterfaceTo (networkInterfaces);
1111 return S_OK;
1112
1113#else
1114 /* Not implemented / supported on this platform. */
1115 ReturnComNotImplemented();
1116#endif
1117}
1118
1119STDMETHODIMP Host::COMGETTER(USBDevices)(IHostUSBDeviceCollection **aUSBDevices)
1120{
1121#ifdef VBOX_WITH_USB
1122 if (!aUSBDevices)
1123 return E_POINTER;
1124
1125 AutoWriteLock alock (this);
1126 CHECK_READY();
1127
1128 MultiResult rc = checkUSBProxyService();
1129 CheckComRCReturnRC (rc);
1130
1131 return mUSBProxyService->getDeviceCollection (aUSBDevices);
1132
1133#else
1134 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1135 * extended error info to indicate that USB is simply not available
1136 * (w/o treting it as a failure), for example, as in OSE */
1137 ReturnComNotImplemented();
1138#endif
1139}
1140
1141STDMETHODIMP Host::COMGETTER(USBDeviceFilters) (IHostUSBDeviceFilterCollection **aUSBDeviceFilters)
1142{
1143#ifdef VBOX_WITH_USB
1144 if (!aUSBDeviceFilters)
1145 return E_POINTER;
1146
1147 AutoWriteLock alock (this);
1148 CHECK_READY();
1149
1150 MultiResult rc = checkUSBProxyService();
1151 CheckComRCReturnRC (rc);
1152
1153 ComObjPtr <HostUSBDeviceFilterCollection> collection;
1154 collection.createObject();
1155 collection->init (mUSBDeviceFilters);
1156 collection.queryInterfaceTo (aUSBDeviceFilters);
1157
1158 return rc;
1159#else
1160 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1161 * extended error info to indicate that USB is simply not available
1162 * (w/o treting it as a failure), for example, as in OSE */
1163 ReturnComNotImplemented();
1164#endif
1165}
1166
1167/**
1168 * Returns the number of installed logical processors
1169 *
1170 * @returns COM status code
1171 * @param count address of result variable
1172 */
1173STDMETHODIMP Host::COMGETTER(ProcessorCount)(ULONG *count)
1174{
1175 if (!count)
1176 return E_POINTER;
1177 AutoWriteLock alock (this);
1178 CHECK_READY();
1179 *count = RTMpGetPresentCount();
1180 return S_OK;
1181}
1182
1183/**
1184 * Returns the number of online logical processors
1185 *
1186 * @returns COM status code
1187 * @param count address of result variable
1188 */
1189STDMETHODIMP Host::COMGETTER(ProcessorOnlineCount)(ULONG *count)
1190{
1191 if (!count)
1192 return E_POINTER;
1193 AutoWriteLock alock (this);
1194 CHECK_READY();
1195 *count = RTMpGetOnlineCount();
1196 return S_OK;
1197}
1198
1199/**
1200 * Returns the (approximate) maximum speed of the given host CPU in MHz
1201 *
1202 * @returns COM status code
1203 * @param cpu id to get info for.
1204 * @param speed address of result variable, speed is 0 if unknown or cpuId is invalid.
1205 */
1206STDMETHODIMP Host::GetProcessorSpeed(ULONG aCpuId, ULONG *speed)
1207{
1208 if (!speed)
1209 return E_POINTER;
1210 AutoWriteLock alock (this);
1211 CHECK_READY();
1212 *speed = RTMpGetMaxFrequency(aCpuId);
1213 return S_OK;
1214}
1215/**
1216 * Returns a description string for the host CPU
1217 *
1218 * @returns COM status code
1219 * @param cpu id to get info for.
1220 * @param description address of result variable, NULL if known or cpuId is invalid.
1221 */
1222STDMETHODIMP Host::GetProcessorDescription(ULONG cpuId, BSTR *description)
1223{
1224 if (!description)
1225 return E_POINTER;
1226 AutoWriteLock alock (this);
1227 CHECK_READY();
1228 /** @todo */
1229 ReturnComNotImplemented();
1230}
1231
1232/**
1233 * Returns whether a host processor feature is supported or not
1234 *
1235 * @returns COM status code
1236 * @param Feature to query.
1237 * @param address of supported bool result variable
1238 */
1239STDMETHODIMP Host::GetProcessorFeature(ProcessorFeature_T feature, BOOL *supported)
1240{
1241 if (!supported)
1242 return E_POINTER;
1243 AutoWriteLock alock (this);
1244 CHECK_READY();
1245
1246 switch (feature)
1247 {
1248 case ProcessorFeature_HWVirtEx:
1249 *supported = fVTxAMDVSupported;
1250 break;
1251
1252 case ProcessorFeature_PAE:
1253 *supported = fPAESupported;
1254 break;
1255
1256 case ProcessorFeature_LongMode:
1257 *supported = fLongModeSupported;
1258 break;
1259
1260 default:
1261 ReturnComNotImplemented();
1262 }
1263 return S_OK;
1264}
1265
1266/**
1267 * Returns the amount of installed system memory in megabytes
1268 *
1269 * @returns COM status code
1270 * @param size address of result variable
1271 */
1272STDMETHODIMP Host::COMGETTER(MemorySize)(ULONG *size)
1273{
1274 if (!size)
1275 return E_POINTER;
1276 AutoWriteLock alock (this);
1277 CHECK_READY();
1278 /* @todo This is an ugly hack. There must be a function in IPRT for that. */
1279 pm::CollectorHAL *hal = pm::createHAL();
1280 if (!hal)
1281 return VERR_INTERNAL_ERROR;
1282 ULONG tmp;
1283 int rc = hal->getHostMemoryUsage(size, &tmp, &tmp);
1284 *size /= 1024;
1285 delete hal;
1286 return rc;
1287}
1288
1289/**
1290 * Returns the current system memory free space in megabytes
1291 *
1292 * @returns COM status code
1293 * @param available address of result variable
1294 */
1295STDMETHODIMP Host::COMGETTER(MemoryAvailable)(ULONG *available)
1296{
1297 if (!available)
1298 return E_POINTER;
1299 AutoWriteLock alock (this);
1300 CHECK_READY();
1301 /* @todo This is an ugly hack. There must be a function in IPRT for that. */
1302 pm::CollectorHAL *hal = pm::createHAL();
1303 if (!hal)
1304 return VERR_INTERNAL_ERROR;
1305 ULONG tmp;
1306 int rc = hal->getHostMemoryUsage(&tmp, &tmp, available);
1307 *available /= 1024;
1308 delete hal;
1309 return rc;
1310}
1311
1312/**
1313 * Returns the name string of the host operating system
1314 *
1315 * @returns COM status code
1316 * @param os address of result variable
1317 */
1318STDMETHODIMP Host::COMGETTER(OperatingSystem)(BSTR *os)
1319{
1320 if (!os)
1321 return E_POINTER;
1322 AutoWriteLock alock (this);
1323 CHECK_READY();
1324 /** @todo */
1325 ReturnComNotImplemented();
1326}
1327
1328/**
1329 * Returns the version string of the host operating system
1330 *
1331 * @returns COM status code
1332 * @param os address of result variable
1333 */
1334STDMETHODIMP Host::COMGETTER(OSVersion)(BSTR *version)
1335{
1336 if (!version)
1337 return E_POINTER;
1338 AutoWriteLock alock (this);
1339 CHECK_READY();
1340 /** @todo */
1341 ReturnComNotImplemented();
1342}
1343
1344/**
1345 * Returns the current host time in milliseconds since 1970-01-01 UTC.
1346 *
1347 * @returns COM status code
1348 * @param time address of result variable
1349 */
1350STDMETHODIMP Host::COMGETTER(UTCTime)(LONG64 *aUTCTime)
1351{
1352 if (!aUTCTime)
1353 return E_POINTER;
1354 AutoWriteLock alock (this);
1355 CHECK_READY();
1356 RTTIMESPEC now;
1357 *aUTCTime = RTTimeSpecGetMilli(RTTimeNow(&now));
1358 return S_OK;
1359}
1360
1361// IHost methods
1362////////////////////////////////////////////////////////////////////////////////
1363
1364#ifdef RT_OS_WINDOWS
1365
1366/**
1367 * Returns TRUE if the Windows version is 6.0 or greater (i.e. it's Vista and
1368 * later OSes) and it has the UAC (User Account Control) feature enabled.
1369 */
1370static BOOL IsUACEnabled()
1371{
1372 LONG rc = 0;
1373
1374 OSVERSIONINFOEX info;
1375 ZeroMemory (&info, sizeof (OSVERSIONINFOEX));
1376 info.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
1377 rc = GetVersionEx ((OSVERSIONINFO *) &info);
1378 AssertReturn (rc != 0, FALSE);
1379
1380 LogFlowFunc (("dwMajorVersion=%d, dwMinorVersion=%d\n",
1381 info.dwMajorVersion, info.dwMinorVersion));
1382
1383 /* we are interested only in Vista (and newer versions...). In all
1384 * earlier versions UAC is not present. */
1385 if (info.dwMajorVersion < 6)
1386 return FALSE;
1387
1388 /* the default EnableLUA value is 1 (Enabled) */
1389 DWORD dwEnableLUA = 1;
1390
1391 HKEY hKey;
1392 rc = RegOpenKeyExA (HKEY_LOCAL_MACHINE,
1393 "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
1394 0, KEY_QUERY_VALUE, &hKey);
1395
1396 Assert (rc == ERROR_SUCCESS || rc == ERROR_PATH_NOT_FOUND);
1397 if (rc == ERROR_SUCCESS)
1398 {
1399
1400 DWORD cbEnableLUA = sizeof (dwEnableLUA);
1401 rc = RegQueryValueExA (hKey, "EnableLUA", NULL, NULL,
1402 (LPBYTE) &dwEnableLUA, &cbEnableLUA);
1403
1404 RegCloseKey (hKey);
1405
1406 Assert (rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND);
1407 }
1408
1409 LogFlowFunc (("rc=%d, dwEnableLUA=%d\n", rc, dwEnableLUA));
1410
1411 return dwEnableLUA == 1;
1412}
1413
1414struct NetworkInterfaceHelperClientData
1415{
1416 SVCHlpMsg::Code msgCode;
1417 /* for SVCHlpMsg::CreateHostNetworkInterface */
1418 Bstr name;
1419 ComObjPtr <HostNetworkInterface> iface;
1420 /* for SVCHlpMsg::RemoveHostNetworkInterface */
1421 Guid guid;
1422};
1423
1424STDMETHODIMP
1425Host::CreateHostNetworkInterface (INPTR BSTR aName,
1426 IHostNetworkInterface **aHostNetworkInterface,
1427 IProgress **aProgress)
1428{
1429 if (!aName)
1430 return E_INVALIDARG;
1431 if (!aHostNetworkInterface)
1432 return E_POINTER;
1433 if (!aProgress)
1434 return E_POINTER;
1435
1436 AutoWriteLock alock (this);
1437 CHECK_READY();
1438
1439 HRESULT rc = S_OK;
1440
1441 /* first check whether an interface with the given name already exists */
1442 {
1443 ComPtr <IHostNetworkInterfaceCollection> coll;
1444 rc = COMGETTER(NetworkInterfaces) (coll.asOutParam());
1445 CheckComRCReturnRC (rc);
1446 ComPtr <IHostNetworkInterface> iface;
1447 if (SUCCEEDED (coll->FindByName (aName, iface.asOutParam())))
1448 return setError (E_FAIL,
1449 tr ("Host network interface '%ls' already exists"), aName);
1450 }
1451
1452 /* create a progress object */
1453 ComObjPtr <Progress> progress;
1454 progress.createObject();
1455 rc = progress->init (mParent, static_cast <IHost *> (this),
1456 Bstr (tr ("Creating host network interface")),
1457 FALSE /* aCancelable */);
1458 CheckComRCReturnRC (rc);
1459 progress.queryInterfaceTo (aProgress);
1460
1461 /* create a new uninitialized host interface object */
1462 ComObjPtr <HostNetworkInterface> iface;
1463 iface.createObject();
1464 iface.queryInterfaceTo (aHostNetworkInterface);
1465
1466 /* create the networkInterfaceHelperClient() argument */
1467 std::auto_ptr <NetworkInterfaceHelperClientData>
1468 d (new NetworkInterfaceHelperClientData());
1469 AssertReturn (d.get(), E_OUTOFMEMORY);
1470
1471 d->msgCode = SVCHlpMsg::CreateHostNetworkInterface;
1472 d->name = aName;
1473 d->iface = iface;
1474
1475 rc = mParent->startSVCHelperClient (
1476 IsUACEnabled() == TRUE /* aPrivileged */,
1477 networkInterfaceHelperClient,
1478 static_cast <void *> (d.get()),
1479 progress);
1480
1481 if (SUCCEEDED (rc))
1482 {
1483 /* d is now owned by networkInterfaceHelperClient(), so release it */
1484 d.release();
1485 }
1486
1487 return rc;
1488}
1489
1490STDMETHODIMP
1491Host::RemoveHostNetworkInterface (INPTR GUIDPARAM aId,
1492 IHostNetworkInterface **aHostNetworkInterface,
1493 IProgress **aProgress)
1494{
1495 if (!aHostNetworkInterface)
1496 return E_POINTER;
1497 if (!aProgress)
1498 return E_POINTER;
1499
1500 AutoWriteLock alock (this);
1501 CHECK_READY();
1502
1503 HRESULT rc = S_OK;
1504
1505 /* first check whether an interface with the given name already exists */
1506 {
1507 ComPtr <IHostNetworkInterfaceCollection> coll;
1508 rc = COMGETTER(NetworkInterfaces) (coll.asOutParam());
1509 CheckComRCReturnRC (rc);
1510 ComPtr <IHostNetworkInterface> iface;
1511 if (FAILED (coll->FindById (aId, iface.asOutParam())))
1512 return setError (E_FAIL,
1513 tr ("Host network interface with UUID {%RTuuid} does not exist"),
1514 Guid (aId).raw());
1515
1516 /* return the object to be removed to the caller */
1517 iface.queryInterfaceTo (aHostNetworkInterface);
1518 }
1519
1520 /* create a progress object */
1521 ComObjPtr <Progress> progress;
1522 progress.createObject();
1523 rc = progress->init (mParent, static_cast <IHost *> (this),
1524 Bstr (tr ("Removing host network interface")),
1525 FALSE /* aCancelable */);
1526 CheckComRCReturnRC (rc);
1527 progress.queryInterfaceTo (aProgress);
1528
1529 /* create the networkInterfaceHelperClient() argument */
1530 std::auto_ptr <NetworkInterfaceHelperClientData>
1531 d (new NetworkInterfaceHelperClientData());
1532 AssertReturn (d.get(), E_OUTOFMEMORY);
1533
1534 d->msgCode = SVCHlpMsg::RemoveHostNetworkInterface;
1535 d->guid = aId;
1536
1537 rc = mParent->startSVCHelperClient (
1538 IsUACEnabled() == TRUE /* aPrivileged */,
1539 networkInterfaceHelperClient,
1540 static_cast <void *> (d.get()),
1541 progress);
1542
1543 if (SUCCEEDED (rc))
1544 {
1545 /* d is now owned by networkInterfaceHelperClient(), so release it */
1546 d.release();
1547 }
1548
1549 return rc;
1550}
1551
1552#endif /* RT_OS_WINDOWS */
1553
1554STDMETHODIMP Host::CreateUSBDeviceFilter (INPTR BSTR aName, IHostUSBDeviceFilter **aFilter)
1555{
1556#ifdef VBOX_WITH_USB
1557 if (!aFilter)
1558 return E_POINTER;
1559
1560 if (!aName || *aName == 0)
1561 return E_INVALIDARG;
1562
1563 AutoWriteLock alock (this);
1564 CHECK_READY();
1565
1566 ComObjPtr <HostUSBDeviceFilter> filter;
1567 filter.createObject();
1568 HRESULT rc = filter->init (this, aName);
1569 ComAssertComRCRet (rc, rc);
1570 rc = filter.queryInterfaceTo (aFilter);
1571 AssertComRCReturn (rc, rc);
1572 return S_OK;
1573#else
1574 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1575 * extended error info to indicate that USB is simply not available
1576 * (w/o treting it as a failure), for example, as in OSE */
1577 ReturnComNotImplemented();
1578#endif
1579}
1580
1581STDMETHODIMP Host::InsertUSBDeviceFilter (ULONG aPosition, IHostUSBDeviceFilter *aFilter)
1582{
1583#ifdef VBOX_WITH_USB
1584 if (!aFilter)
1585 return E_INVALIDARG;
1586
1587 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1588 AutoWriteLock alock (this);
1589 CHECK_READY();
1590
1591 MultiResult rc = checkUSBProxyService();
1592 CheckComRCReturnRC (rc);
1593
1594 ComObjPtr <HostUSBDeviceFilter> filter = getDependentChild (aFilter);
1595 if (!filter)
1596 return setError (E_INVALIDARG,
1597 tr ("The given USB device filter is not created within "
1598 "this VirtualBox instance"));
1599
1600 if (filter->mInList)
1601 return setError (E_INVALIDARG,
1602 tr ("The given USB device filter is already in the list"));
1603
1604 /* iterate to the position... */
1605 USBDeviceFilterList::iterator it = mUSBDeviceFilters.begin();
1606 std::advance (it, aPosition);
1607 /* ...and insert */
1608 mUSBDeviceFilters.insert (it, filter);
1609 filter->mInList = true;
1610
1611 /* notify the proxy (only when the filter is active) */
1612 if (mUSBProxyService->isActive() && filter->data().mActive)
1613 {
1614 ComAssertRet (filter->id() == NULL, E_FAIL);
1615 filter->id() = mUSBProxyService->insertFilter (&filter->data().mUSBFilter);
1616 }
1617
1618 /* save the global settings */
1619 alock.unlock();
1620 return rc = mParent->saveSettings();
1621#else
1622 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1623 * extended error info to indicate that USB is simply not available
1624 * (w/o treting it as a failure), for example, as in OSE */
1625 ReturnComNotImplemented();
1626#endif
1627}
1628
1629STDMETHODIMP Host::RemoveUSBDeviceFilter (ULONG aPosition, IHostUSBDeviceFilter **aFilter)
1630{
1631#ifdef VBOX_WITH_USB
1632 if (!aFilter)
1633 return E_POINTER;
1634
1635 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1636 AutoWriteLock alock (this);
1637 CHECK_READY();
1638
1639 MultiResult rc = checkUSBProxyService();
1640 CheckComRCReturnRC (rc);
1641
1642 if (!mUSBDeviceFilters.size())
1643 return setError (E_INVALIDARG,
1644 tr ("The USB device filter list is empty"));
1645
1646 if (aPosition >= mUSBDeviceFilters.size())
1647 return setError (E_INVALIDARG,
1648 tr ("Invalid position: %lu (must be in range [0, %lu])"),
1649 aPosition, mUSBDeviceFilters.size() - 1);
1650
1651 ComObjPtr <HostUSBDeviceFilter> filter;
1652 {
1653 /* iterate to the position... */
1654 USBDeviceFilterList::iterator it = mUSBDeviceFilters.begin();
1655 std::advance (it, aPosition);
1656 /* ...get an element from there... */
1657 filter = *it;
1658 /* ...and remove */
1659 filter->mInList = false;
1660 mUSBDeviceFilters.erase (it);
1661 }
1662
1663 filter.queryInterfaceTo (aFilter);
1664
1665 /* notify the proxy (only when the filter is active) */
1666 if (mUSBProxyService->isActive() && filter->data().mActive)
1667 {
1668 ComAssertRet (filter->id() != NULL, E_FAIL);
1669 mUSBProxyService->removeFilter (filter->id());
1670 filter->id() = NULL;
1671 }
1672
1673 /* save the global settings */
1674 alock.unlock();
1675 return rc = mParent->saveSettings();
1676#else
1677 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1678 * extended error info to indicate that USB is simply not available
1679 * (w/o treting it as a failure), for example, as in OSE */
1680 ReturnComNotImplemented();
1681#endif
1682}
1683
1684// public methods only for internal purposes
1685////////////////////////////////////////////////////////////////////////////////
1686
1687HRESULT Host::loadSettings (const settings::Key &aGlobal)
1688{
1689 using namespace settings;
1690
1691 AutoWriteLock alock (this);
1692 CHECK_READY();
1693
1694 AssertReturn (!aGlobal.isNull(), E_FAIL);
1695
1696 HRESULT rc = S_OK;
1697
1698#ifdef VBOX_WITH_USB
1699 Key::List filters = aGlobal.key ("USBDeviceFilters").keys ("DeviceFilter");
1700 for (Key::List::const_iterator it = filters.begin();
1701 it != filters.end(); ++ it)
1702 {
1703 Bstr name = (*it).stringValue ("name");
1704 bool active = (*it).value <bool> ("active");
1705
1706 Bstr vendorId = (*it).stringValue ("vendorId");
1707 Bstr productId = (*it).stringValue ("productId");
1708 Bstr revision = (*it).stringValue ("revision");
1709 Bstr manufacturer = (*it).stringValue ("manufacturer");
1710 Bstr product = (*it).stringValue ("product");
1711 Bstr serialNumber = (*it).stringValue ("serialNumber");
1712 Bstr port = (*it).stringValue ("port");
1713
1714 USBDeviceFilterAction_T action;
1715 action = USBDeviceFilterAction_Ignore;
1716 const char *actionStr = (*it).stringValue ("action");
1717 if (strcmp (actionStr, "Ignore") == 0)
1718 action = USBDeviceFilterAction_Ignore;
1719 else
1720 if (strcmp (actionStr, "Hold") == 0)
1721 action = USBDeviceFilterAction_Hold;
1722 else
1723 AssertMsgFailed (("Invalid action: '%s'\n", actionStr));
1724
1725 ComObjPtr <HostUSBDeviceFilter> filterObj;
1726 filterObj.createObject();
1727 rc = filterObj->init (this,
1728 name, active, vendorId, productId, revision,
1729 manufacturer, product, serialNumber, port,
1730 action);
1731 /* error info is set by init() when appropriate */
1732 CheckComRCBreakRC (rc);
1733
1734 mUSBDeviceFilters.push_back (filterObj);
1735 filterObj->mInList = true;
1736
1737 /* notify the proxy (only when the filter is active) */
1738 if (filterObj->data().mActive)
1739 {
1740 HostUSBDeviceFilter *flt = filterObj; /* resolve ambiguity */
1741 flt->id() = mUSBProxyService->insertFilter (&filterObj->data().mUSBFilter);
1742 }
1743 }
1744#endif /* VBOX_WITH_USB */
1745
1746 return rc;
1747}
1748
1749HRESULT Host::saveSettings (settings::Key &aGlobal)
1750{
1751 using namespace settings;
1752
1753 AutoWriteLock alock (this);
1754 CHECK_READY();
1755
1756 ComAssertRet (!aGlobal.isNull(), E_FAIL);
1757
1758#ifdef VBOX_WITH_USB
1759 /* first, delete the entry */
1760 Key filters = aGlobal.findKey ("USBDeviceFilters");
1761 if (!filters.isNull())
1762 filters.zap();
1763 /* then, recreate it */
1764 filters = aGlobal.createKey ("USBDeviceFilters");
1765
1766 USBDeviceFilterList::const_iterator it = mUSBDeviceFilters.begin();
1767 while (it != mUSBDeviceFilters.end())
1768 {
1769 AutoWriteLock filterLock (*it);
1770 const HostUSBDeviceFilter::Data &data = (*it)->data();
1771
1772 Key filter = filters.appendKey ("DeviceFilter");
1773
1774 filter.setValue <Bstr> ("name", data.mName);
1775 filter.setValue <bool> ("active", !!data.mActive);
1776
1777 /* all are optional */
1778 Bstr str;
1779 (*it)->COMGETTER (VendorId) (str.asOutParam());
1780 if (!str.isNull())
1781 filter.setValue <Bstr> ("vendorId", str);
1782
1783 (*it)->COMGETTER (ProductId) (str.asOutParam());
1784 if (!str.isNull())
1785 filter.setValue <Bstr> ("productId", str);
1786
1787 (*it)->COMGETTER (Revision) (str.asOutParam());
1788 if (!str.isNull())
1789 filter.setValue <Bstr> ("revision", str);
1790
1791 (*it)->COMGETTER (Manufacturer) (str.asOutParam());
1792 if (!str.isNull())
1793 filter.setValue <Bstr> ("manufacturer", str);
1794
1795 (*it)->COMGETTER (Product) (str.asOutParam());
1796 if (!str.isNull())
1797 filter.setValue <Bstr> ("product", str);
1798
1799 (*it)->COMGETTER (SerialNumber) (str.asOutParam());
1800 if (!str.isNull())
1801 filter.setValue <Bstr> ("serialNumber", str);
1802
1803 (*it)->COMGETTER (Port) (str.asOutParam());
1804 if (!str.isNull())
1805 filter.setValue <Bstr> ("port", str);
1806
1807 /* action is mandatory */
1808 USBDeviceFilterAction_T action = USBDeviceFilterAction_Null;
1809 (*it)->COMGETTER (Action) (&action);
1810 if (action == USBDeviceFilterAction_Ignore)
1811 filter.setStringValue ("action", "Ignore");
1812 else if (action == USBDeviceFilterAction_Hold)
1813 filter.setStringValue ("action", "Hold");
1814 else
1815 AssertMsgFailed (("Invalid action: %d\n", action));
1816
1817 ++ it;
1818 }
1819#endif /* VBOX_WITH_USB */
1820
1821 return S_OK;
1822}
1823
1824#ifdef VBOX_WITH_USB
1825/**
1826 * Called by setter methods of all USB device filters.
1827 */
1828HRESULT Host::onUSBDeviceFilterChange (HostUSBDeviceFilter *aFilter,
1829 BOOL aActiveChanged /* = FALSE */)
1830{
1831 AutoWriteLock alock (this);
1832 CHECK_READY();
1833
1834 if (aFilter->mInList)
1835 {
1836 if (aActiveChanged)
1837 {
1838 // insert/remove the filter from the proxy
1839 if (aFilter->data().mActive)
1840 {
1841 ComAssertRet (aFilter->id() == NULL, E_FAIL);
1842 aFilter->id() = mUSBProxyService->insertFilter (&aFilter->data().mUSBFilter);
1843 }
1844 else
1845 {
1846 ComAssertRet (aFilter->id() != NULL, E_FAIL);
1847 mUSBProxyService->removeFilter (aFilter->id());
1848 aFilter->id() = NULL;
1849 }
1850 }
1851 else
1852 {
1853 if (aFilter->data().mActive)
1854 {
1855 // update the filter in the proxy
1856 ComAssertRet (aFilter->id() != NULL, E_FAIL);
1857 mUSBProxyService->removeFilter (aFilter->id());
1858 aFilter->id() = mUSBProxyService->insertFilter (&aFilter->data().mUSBFilter);
1859 }
1860 }
1861
1862 // save the global settings... yeah, on every single filter property change
1863 alock.unlock();
1864 return mParent->saveSettings();
1865 }
1866
1867 return S_OK;
1868}
1869
1870
1871/**
1872 * Interface for obtaining a copy of the USBDeviceFilterList,
1873 * used by the USBProxyService.
1874 *
1875 * @param aGlobalFilters Where to put the global filter list copy.
1876 * @param aMachines Where to put the machine vector.
1877 */
1878void Host::getUSBFilters(Host::USBDeviceFilterList *aGlobalFilters, VirtualBox::SessionMachineVector *aMachines)
1879{
1880 AutoWriteLock alock (this);
1881
1882 mParent->getOpenedMachines (*aMachines);
1883 *aGlobalFilters = mUSBDeviceFilters;
1884}
1885
1886#endif /* VBOX_WITH_USB */
1887
1888// private methods
1889////////////////////////////////////////////////////////////////////////////////
1890
1891#if defined(RT_OS_LINUX) && defined(VBOX_WITH_LIBHAL)
1892/* Linux, load libhal statically */
1893
1894/** Helper function for setting up a libhal context */
1895bool hostInitLibHal(DBusConnection **pDBusConnection,
1896 LibHalContext **pLibHalContext)
1897{
1898 bool halSuccess = true;
1899 DBusError dbusError;
1900
1901 dbus_error_init (&dbusError);
1902 DBusConnection *dbusConnection;
1903 LibHalContext *libhalContext;
1904 dbusConnection = dbus_bus_get (DBUS_BUS_SYSTEM, &dbusError);
1905 if (dbusConnection == NULL)
1906 halSuccess = false;
1907 if (dbusConnection == NULL && !dbus_error_is_set (&dbusError))
1908 LogRelFunc (("Unresolved error getting DBus connection.\n"));
1909 if (halSuccess)
1910 {
1911 libhalContext = libhal_ctx_new();
1912 if (libhalContext == NULL)
1913 halSuccess = false;
1914 }
1915 if ( halSuccess
1916 && !libhal_ctx_set_dbus_connection (libhalContext, dbusConnection))
1917 halSuccess = false;
1918 if ( halSuccess
1919 && !libhal_ctx_init (libhalContext, &dbusError))
1920 {
1921 halSuccess = false;
1922 if (!dbus_error_is_set (&dbusError))
1923 LogRelFunc (("Unresolved error initialising the libhal context.\n"));
1924 }
1925 if (halSuccess)
1926 {
1927 *pDBusConnection = dbusConnection;
1928 *pLibHalContext = libhalContext;
1929 }
1930 return halSuccess;
1931}
1932
1933/**
1934 * Helper function to query the hal subsystem for information about DVD drives attached to the
1935 * system.
1936 *
1937 * @returns true if information was successfully obtained, false otherwise
1938 * @retval list drives found will be attached to this list
1939 */
1940bool Host::getDVDInfoFromHal(std::list <ComObjPtr <HostDVDDrive> > &list)
1941{
1942 DBusConnection *dbusConnection;
1943 LibHalContext *libhalContext;
1944 int numDevices = 0;
1945 char **halDevices = NULL;
1946 bool halSuccess = hostInitLibHal (&dbusConnection, &libhalContext);
1947 if (halSuccess)
1948 halDevices = libhal_manager_find_device_string_match(libhalContext,
1949 "storage.drive_type", "cdrom",
1950 &numDevices, NULL);
1951 /* Hal is installed and working, so if no devices are reported, assume
1952 that there are none. */
1953 for (int i = 0; halSuccess && i < numDevices; ++i)
1954 {
1955 char *devNode = libhal_device_get_property_string(libhalContext,
1956 halDevices[i], "block.device", NULL);
1957 Utf8Str description;
1958 char *vendor = NULL, *product = NULL;
1959 if (devNode != NULL)
1960 {
1961 vendor = libhal_device_get_property_string(libhalContext,
1962 halDevices[i], "info.vendor", NULL);
1963 product = libhal_device_get_property_string(libhalContext,
1964 halDevices[i], "info.product", NULL);
1965 if ((product != 0 && product[0] != 0))
1966 {
1967 if ((vendor != 0) && (vendor[0] != 0))
1968 description = Utf8StrFmt ("%s %s",
1969 vendor, product);
1970 else
1971 description = product;
1972 }
1973 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
1974 hostDVDDriveObj.createObject();
1975 if (!description.isNull ())
1976 hostDVDDriveObj->init (Bstr (devNode),
1977 Bstr (halDevices[i]),
1978 Bstr (description));
1979 else
1980 hostDVDDriveObj->init (Bstr (devNode),
1981 Bstr (halDevices[i]));
1982 list.push_back (hostDVDDriveObj);
1983 if (vendor != NULL)
1984 libhal_free_string(vendor);
1985 if (product != NULL)
1986 libhal_free_string(product);
1987 libhal_free_string(devNode);
1988 }
1989 }
1990 if (halDevices != NULL)
1991 libhal_free_string_array(halDevices);
1992 if (halSuccess)
1993 libhal_ctx_shutdown (libhalContext, NULL);
1994 if (libhalContext != NULL)
1995 libhal_ctx_free (libhalContext);
1996 if (dbusConnection != NULL)
1997 dbus_connection_unref (dbusConnection);
1998 return halSuccess;
1999}
2000
2001/**
2002 * Helper function to query the hal subsystem for information about floppy drives attached to the
2003 * system.
2004 *
2005 * @returns true if information was successfully obtained, false otherwise
2006 * @retval list drives found will be attached to this list
2007 */
2008bool Host::getFloppyInfoFromHal(std::list <ComObjPtr <HostFloppyDrive> > &list)
2009{
2010 DBusConnection *dbusConnection;
2011 LibHalContext *libhalContext;
2012 int numDevices = 0;
2013 char **halDevices = NULL;
2014 bool halSuccess = hostInitLibHal (&dbusConnection, &libhalContext);
2015 if (halSuccess)
2016 halDevices = libhal_manager_find_device_string_match(libhalContext,
2017 "storage.drive_type", "floppy",
2018 &numDevices, NULL);
2019 /* Hal is installed and working, so if no devices are reported, assume
2020 that there are none. */
2021 for (int i = 0; halSuccess && i < numDevices; ++i)
2022 {
2023 char *devNode = libhal_device_get_property_string(libhalContext,
2024 halDevices[i], "block.device", NULL);
2025 Utf8Str description;
2026 char *vendor = NULL, *product = NULL;
2027 if (devNode != NULL)
2028 {
2029 vendor = libhal_device_get_property_string(libhalContext,
2030 halDevices[i], "info.vendor", NULL);
2031 product = libhal_device_get_property_string(libhalContext,
2032 halDevices[i], "info.product", NULL);
2033 if ((product != 0 && product[0] != 0))
2034 {
2035 if ((vendor != 0) && (vendor[0] != 0))
2036 description = Utf8StrFmt ("%s %s",
2037 vendor, product);
2038 else
2039 description = product;
2040 }
2041 ComObjPtr <HostFloppyDrive> hostFloppyDriveObj;
2042 hostFloppyDriveObj.createObject();
2043 if (!description.isNull ())
2044 hostFloppyDriveObj->init (Bstr (devNode),
2045 Bstr (halDevices[i]),
2046 Bstr (description));
2047 else
2048 hostFloppyDriveObj->init (Bstr (devNode),
2049 Bstr (halDevices[i]));
2050 list.push_back (hostFloppyDriveObj);
2051 if (vendor != NULL)
2052 libhal_free_string(vendor);
2053 if (product != NULL)
2054 libhal_free_string(product);
2055 libhal_free_string(devNode);
2056 }
2057 }
2058 if (halDevices != NULL)
2059 libhal_free_string_array(halDevices);
2060 if (halSuccess)
2061 libhal_ctx_shutdown (libhalContext, NULL);
2062 if (libhalContext != NULL)
2063 libhal_ctx_free (libhalContext);
2064 if (dbusConnection != NULL)
2065 dbus_connection_unref (dbusConnection);
2066 return halSuccess;
2067}
2068
2069# elif defined(RT_OS_SOLARIS) && defined(VBOX_USE_LIBHAL)
2070/* Solaris hosts, loading libhal at runtime */
2071
2072/**
2073 * Helper function to query the hal subsystem for information about DVD drives attached to the
2074 * system.
2075 *
2076 * @returns true if information was successfully obtained, false otherwise
2077 * @retval list drives found will be attached to this list
2078 */
2079bool Host::getDVDInfoFromHal(std::list <ComObjPtr <HostDVDDrive> > &list)
2080{
2081 bool halSuccess = false;
2082 DBusError dbusError;
2083 if (!gLibHalCheckPresence())
2084 return false;
2085 gDBusErrorInit (&dbusError);
2086 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
2087 if (dbusConnection != 0)
2088 {
2089 LibHalContext *halContext = gLibHalCtxNew();
2090 if (halContext != 0)
2091 {
2092 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
2093 {
2094 if (gLibHalCtxInit(halContext, &dbusError))
2095 {
2096 int numDevices;
2097 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
2098 "storage.drive_type", "cdrom",
2099 &numDevices, &dbusError);
2100 if (halDevices != 0)
2101 {
2102 /* Hal is installed and working, so if no devices are reported, assume
2103 that there are none. */
2104 halSuccess = true;
2105 for (int i = 0; i < numDevices; i++)
2106 {
2107 char *devNode = gLibHalDeviceGetPropertyString(halContext,
2108 halDevices[i], "block.device", &dbusError);
2109#ifdef RT_OS_SOLARIS
2110 /* The CD/DVD ioctls work only for raw device nodes. */
2111 char *tmp = getfullrawname(devNode);
2112 gLibHalFreeString(devNode);
2113 devNode = tmp;
2114#endif
2115 if (devNode != 0)
2116 {
2117// if (validateDevice(devNode, true))
2118// {
2119 Utf8Str description;
2120 char *vendor, *product;
2121 /* We do not check the error here, as this field may
2122 not even exist. */
2123 vendor = gLibHalDeviceGetPropertyString(halContext,
2124 halDevices[i], "info.vendor", 0);
2125 product = gLibHalDeviceGetPropertyString(halContext,
2126 halDevices[i], "info.product", &dbusError);
2127 if ((product != 0 && product[0] != 0))
2128 {
2129 if ((vendor != 0) && (vendor[0] != 0))
2130 {
2131 description = Utf8StrFmt ("%s %s",
2132 vendor, product);
2133 }
2134 else
2135 {
2136 description = product;
2137 }
2138 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
2139 hostDVDDriveObj.createObject();
2140 hostDVDDriveObj->init (Bstr (devNode),
2141 Bstr (halDevices[i]),
2142 Bstr (description));
2143 list.push_back (hostDVDDriveObj);
2144 }
2145 else
2146 {
2147 if (product == 0)
2148 {
2149 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
2150 halDevices[i], dbusError.name, dbusError.message));
2151 gDBusErrorFree(&dbusError);
2152 }
2153 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
2154 hostDVDDriveObj.createObject();
2155 hostDVDDriveObj->init (Bstr (devNode),
2156 Bstr (halDevices[i]));
2157 list.push_back (hostDVDDriveObj);
2158 }
2159 if (vendor != 0)
2160 {
2161 gLibHalFreeString(vendor);
2162 }
2163 if (product != 0)
2164 {
2165 gLibHalFreeString(product);
2166 }
2167// }
2168// else
2169// {
2170// LogRel(("Host::COMGETTER(DVDDrives): failed to validate the block device %s as a DVD drive\n"));
2171// }
2172#ifndef RT_OS_SOLARIS
2173 gLibHalFreeString(devNode);
2174#else
2175 free(devNode);
2176#endif
2177 }
2178 else
2179 {
2180 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
2181 halDevices[i], dbusError.name, dbusError.message));
2182 gDBusErrorFree(&dbusError);
2183 }
2184 }
2185 gLibHalFreeStringArray(halDevices);
2186 }
2187 else
2188 {
2189 LogRel(("Host::COMGETTER(DVDDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2190 gDBusErrorFree(&dbusError);
2191 }
2192 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
2193 {
2194 LogRel(("Host::COMGETTER(DVDDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2195 gDBusErrorFree(&dbusError);
2196 }
2197 }
2198 else
2199 {
2200 LogRel(("Host::COMGETTER(DVDDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2201 gDBusErrorFree(&dbusError);
2202 }
2203 gLibHalCtxFree(halContext);
2204 }
2205 else
2206 {
2207 LogRel(("Host::COMGETTER(DVDDrives): failed to set libhal connection to dbus.\n"));
2208 }
2209 }
2210 else
2211 {
2212 LogRel(("Host::COMGETTER(DVDDrives): failed to get a libhal context - out of memory?\n"));
2213 }
2214 gDBusConnectionUnref(dbusConnection);
2215 }
2216 else
2217 {
2218 LogRel(("Host::COMGETTER(DVDDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2219 gDBusErrorFree(&dbusError);
2220 }
2221 return halSuccess;
2222}
2223
2224
2225/**
2226 * Helper function to query the hal subsystem for information about floppy drives attached to the
2227 * system.
2228 *
2229 * @returns true if information was successfully obtained, false otherwise
2230 * @retval list drives found will be attached to this list
2231 */
2232bool Host::getFloppyInfoFromHal(std::list <ComObjPtr <HostFloppyDrive> > &list)
2233{
2234 bool halSuccess = false;
2235 DBusError dbusError;
2236 if (!gLibHalCheckPresence())
2237 return false;
2238 gDBusErrorInit (&dbusError);
2239 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
2240 if (dbusConnection != 0)
2241 {
2242 LibHalContext *halContext = gLibHalCtxNew();
2243 if (halContext != 0)
2244 {
2245 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
2246 {
2247 if (gLibHalCtxInit(halContext, &dbusError))
2248 {
2249 int numDevices;
2250 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
2251 "storage.drive_type", "floppy",
2252 &numDevices, &dbusError);
2253 if (halDevices != 0)
2254 {
2255 /* Hal is installed and working, so if no devices are reported, assume
2256 that there are none. */
2257 halSuccess = true;
2258 for (int i = 0; i < numDevices; i++)
2259 {
2260 char *driveType = gLibHalDeviceGetPropertyString(halContext,
2261 halDevices[i], "storage.drive_type", 0);
2262 if (driveType != 0)
2263 {
2264 if (strcmp(driveType, "floppy") != 0)
2265 {
2266 gLibHalFreeString(driveType);
2267 continue;
2268 }
2269 gLibHalFreeString(driveType);
2270 }
2271 else
2272 {
2273 /* An error occurred. The attribute "storage.drive_type"
2274 probably didn't exist. */
2275 continue;
2276 }
2277 char *devNode = gLibHalDeviceGetPropertyString(halContext,
2278 halDevices[i], "block.device", &dbusError);
2279 if (devNode != 0)
2280 {
2281// if (validateDevice(devNode, false))
2282// {
2283 Utf8Str description;
2284 char *vendor, *product;
2285 /* We do not check the error here, as this field may
2286 not even exist. */
2287 vendor = gLibHalDeviceGetPropertyString(halContext,
2288 halDevices[i], "info.vendor", 0);
2289 product = gLibHalDeviceGetPropertyString(halContext,
2290 halDevices[i], "info.product", &dbusError);
2291 if ((product != 0) && (product[0] != 0))
2292 {
2293 if ((vendor != 0) && (vendor[0] != 0))
2294 {
2295 description = Utf8StrFmt ("%s %s",
2296 vendor, product);
2297 }
2298 else
2299 {
2300 description = product;
2301 }
2302 ComObjPtr <HostFloppyDrive> hostFloppyDrive;
2303 hostFloppyDrive.createObject();
2304 hostFloppyDrive->init (Bstr (devNode),
2305 Bstr (halDevices[i]),
2306 Bstr (description));
2307 list.push_back (hostFloppyDrive);
2308 }
2309 else
2310 {
2311 if (product == 0)
2312 {
2313 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
2314 halDevices[i], dbusError.name, dbusError.message));
2315 gDBusErrorFree(&dbusError);
2316 }
2317 ComObjPtr <HostFloppyDrive> hostFloppyDrive;
2318 hostFloppyDrive.createObject();
2319 hostFloppyDrive->init (Bstr (devNode),
2320 Bstr (halDevices[i]));
2321 list.push_back (hostFloppyDrive);
2322 }
2323 if (vendor != 0)
2324 {
2325 gLibHalFreeString(vendor);
2326 }
2327 if (product != 0)
2328 {
2329 gLibHalFreeString(product);
2330 }
2331// }
2332// else
2333// {
2334// LogRel(("Host::COMGETTER(FloppyDrives): failed to validate the block device %s as a floppy drive\n"));
2335// }
2336 gLibHalFreeString(devNode);
2337 }
2338 else
2339 {
2340 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
2341 halDevices[i], dbusError.name, dbusError.message));
2342 gDBusErrorFree(&dbusError);
2343 }
2344 }
2345 gLibHalFreeStringArray(halDevices);
2346 }
2347 else
2348 {
2349 LogRel(("Host::COMGETTER(FloppyDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2350 gDBusErrorFree(&dbusError);
2351 }
2352 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
2353 {
2354 LogRel(("Host::COMGETTER(FloppyDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2355 gDBusErrorFree(&dbusError);
2356 }
2357 }
2358 else
2359 {
2360 LogRel(("Host::COMGETTER(FloppyDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2361 gDBusErrorFree(&dbusError);
2362 }
2363 gLibHalCtxFree(halContext);
2364 }
2365 else
2366 {
2367 LogRel(("Host::COMGETTER(FloppyDrives): failed to set libhal connection to dbus.\n"));
2368 }
2369 }
2370 else
2371 {
2372 LogRel(("Host::COMGETTER(FloppyDrives): failed to get a libhal context - out of memory?\n"));
2373 }
2374 gDBusConnectionUnref(dbusConnection);
2375 }
2376 else
2377 {
2378 LogRel(("Host::COMGETTER(FloppyDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2379 gDBusErrorFree(&dbusError);
2380 }
2381 return halSuccess;
2382}
2383#endif /* VBOX_WITH_HAL and VBOX_USE_HAL */
2384
2385#if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)
2386
2387/**
2388 * Helper function to parse the given mount file and add found entries
2389 */
2390void Host::parseMountTable(char *mountTable, std::list <ComObjPtr <HostDVDDrive> > &list)
2391{
2392#ifdef RT_OS_LINUX
2393 FILE *mtab = setmntent(mountTable, "r");
2394 if (mtab)
2395 {
2396 struct mntent *mntent;
2397 char *mnt_type;
2398 char *mnt_dev;
2399 char *tmp;
2400 while ((mntent = getmntent(mtab)))
2401 {
2402 mnt_type = (char*)malloc(strlen(mntent->mnt_type) + 1);
2403 mnt_dev = (char*)malloc(strlen(mntent->mnt_fsname) + 1);
2404 strcpy(mnt_type, mntent->mnt_type);
2405 strcpy(mnt_dev, mntent->mnt_fsname);
2406 // supermount fs case
2407 if (strcmp(mnt_type, "supermount") == 0)
2408 {
2409 tmp = strstr(mntent->mnt_opts, "fs=");
2410 if (tmp)
2411 {
2412 free(mnt_type);
2413 mnt_type = strdup(tmp + strlen("fs="));
2414 if (mnt_type)
2415 {
2416 tmp = strchr(mnt_type, ',');
2417 if (tmp)
2418 *tmp = '\0';
2419 }
2420 }
2421 tmp = strstr(mntent->mnt_opts, "dev=");
2422 if (tmp)
2423 {
2424 free(mnt_dev);
2425 mnt_dev = strdup(tmp + strlen("dev="));
2426 if (mnt_dev)
2427 {
2428 tmp = strchr(mnt_dev, ',');
2429 if (tmp)
2430 *tmp = '\0';
2431 }
2432 }
2433 }
2434 // use strstr here to cover things fs types like "udf,iso9660"
2435 if (strstr(mnt_type, "iso9660") == 0)
2436 {
2437 /** @todo check whether we've already got the drive in our list! */
2438 if (validateDevice(mnt_dev, true))
2439 {
2440 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
2441 hostDVDDriveObj.createObject();
2442 hostDVDDriveObj->init (Bstr (mnt_dev));
2443 list.push_back (hostDVDDriveObj);
2444 }
2445 }
2446 free(mnt_dev);
2447 free(mnt_type);
2448 }
2449 endmntent(mtab);
2450 }
2451#else // RT_OS_SOLARIS
2452 FILE *mntFile = fopen(mountTable, "r");
2453 if (mntFile)
2454 {
2455 struct mnttab mntTab;
2456 while (getmntent(mntFile, &mntTab) == 0)
2457 {
2458 char *mountName = strdup(mntTab.mnt_special);
2459 char *mountPoint = strdup(mntTab.mnt_mountp);
2460 char *mountFSType = strdup(mntTab.mnt_fstype);
2461
2462 // skip devices we are not interested in
2463 if ((*mountName && mountName[0] == '/') && // skip 'fake' devices (like -hosts, proc, fd, swap)
2464 (*mountFSType && (strcmp(mountFSType, "devfs") != 0 && // skip devfs (i.e. /devices)
2465 strcmp(mountFSType, "dev") != 0 && // skip dev (i.e. /dev)
2466 strcmp(mountFSType, "lofs") != 0)) && // skip loop-back file-system (lofs)
2467 (*mountPoint && strcmp(mountPoint, "/") != 0)) // skip point '/' (Can CD/DVD be mounted at '/' ???)
2468 {
2469 char *rawDevName = getfullrawname(mountName);
2470 if (validateDevice(rawDevName, true))
2471 {
2472 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
2473 hostDVDDriveObj.createObject();
2474 hostDVDDriveObj->init (Bstr (rawDevName));
2475 list.push_back (hostDVDDriveObj);
2476 }
2477 free(rawDevName);
2478 }
2479
2480 free(mountName);
2481 free(mountPoint);
2482 free(mountFSType);
2483 }
2484
2485 fclose(mntFile);
2486 }
2487#endif
2488}
2489
2490/**
2491 * Helper function to check whether the given device node is a valid drive
2492 */
2493bool Host::validateDevice(const char *deviceNode, bool isCDROM)
2494{
2495 struct stat statInfo;
2496 bool retValue = false;
2497
2498 // sanity check
2499 if (!deviceNode)
2500 {
2501 return false;
2502 }
2503
2504 // first a simple stat() call
2505 if (stat(deviceNode, &statInfo) < 0)
2506 {
2507 return false;
2508 } else
2509 {
2510 if (isCDROM)
2511 {
2512 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2513 {
2514 int fileHandle;
2515 // now try to open the device
2516 fileHandle = open(deviceNode, O_RDONLY | O_NONBLOCK, 0);
2517 if (fileHandle >= 0)
2518 {
2519 cdrom_subchnl cdChannelInfo;
2520 cdChannelInfo.cdsc_format = CDROM_MSF;
2521 // this call will finally reveal the whole truth
2522#ifdef RT_OS_LINUX
2523 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2524 (errno == EIO) || (errno == ENOENT) ||
2525 (errno == EINVAL) || (errno == ENOMEDIUM))
2526#else
2527 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2528 (errno == EIO) || (errno == ENOENT) ||
2529 (errno == EINVAL))
2530#endif
2531 {
2532 retValue = true;
2533 }
2534 close(fileHandle);
2535 }
2536 }
2537 } else
2538 {
2539 // floppy case
2540 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2541 {
2542 /// @todo do some more testing, maybe a nice IOCTL!
2543 retValue = true;
2544 }
2545 }
2546 }
2547 return retValue;
2548}
2549#endif // RT_OS_LINUX || RT_OS_SOLARIS
2550
2551#ifdef VBOX_WITH_USB
2552/**
2553 * Checks for the presense and status of the USB Proxy Service.
2554 * Returns S_OK when the Proxy is present and OK, or E_FAIL and a
2555 * corresponding error message otherwise. Intended to be used by methods
2556 * that rely on the Proxy Service availability.
2557 *
2558 * @note This method may return a warning result code. It is recommended to use
2559 * MultiError to store the return value.
2560 *
2561 * @note Locks this object for reading.
2562 */
2563HRESULT Host::checkUSBProxyService()
2564{
2565 AutoWriteLock alock (this);
2566 CHECK_READY();
2567
2568 AssertReturn (mUSBProxyService, E_FAIL);
2569 if (!mUSBProxyService->isActive())
2570 {
2571 /* disable the USB controller completely to avoid assertions if the
2572 * USB proxy service could not start. */
2573
2574 if (mUSBProxyService->getLastError() == VERR_FILE_NOT_FOUND)
2575 return setWarning (E_FAIL,
2576 tr ("Could not load the Host USB Proxy Service (%Rrc). "
2577 "The service might be not installed on the host computer"),
2578 mUSBProxyService->getLastError());
2579 if (mUSBProxyService->getLastError() == VINF_SUCCESS)
2580 return setWarning (E_FAIL,
2581 tr ("The USB Proxy Service has not yet been ported to this host"));
2582 return setWarning (E_FAIL,
2583 tr ("Could not load the Host USB Proxy service (%Rrc)"),
2584 mUSBProxyService->getLastError());
2585 }
2586
2587 return S_OK;
2588}
2589#endif /* VBOX_WITH_USB */
2590
2591#ifdef RT_OS_WINDOWS
2592
2593/* The original source of the VBoxTAP adapter creation/destruction code has the following copyright */
2594/*
2595 Copyright 2004 by the Massachusetts Institute of Technology
2596
2597 All rights reserved.
2598
2599 Permission to use, copy, modify, and distribute this software and its
2600 documentation for any purpose and without fee is hereby granted,
2601 provided that the above copyright notice appear in all copies and that
2602 both that copyright notice and this permission notice appear in
2603 supporting documentation, and that the name of the Massachusetts
2604 Institute of Technology (M.I.T.) not be used in advertising or publicity
2605 pertaining to distribution of the software without specific, written
2606 prior permission.
2607
2608 M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2609 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2610 M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2611 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2612 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2613 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2614 SOFTWARE.
2615*/
2616
2617
2618#define NETSHELL_LIBRARY _T("netshell.dll")
2619
2620/**
2621 * Use the IShellFolder API to rename the connection.
2622 */
2623static HRESULT rename_shellfolder (PCWSTR wGuid, PCWSTR wNewName)
2624{
2625 /* This is the GUID for the network connections folder. It is constant.
2626 * {7007ACC7-3202-11D1-AAD2-00805FC1270E} */
2627 const GUID CLSID_NetworkConnections = {
2628 0x7007ACC7, 0x3202, 0x11D1, {
2629 0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E
2630 }
2631 };
2632
2633 LPITEMIDLIST pidl = NULL;
2634 IShellFolder *pShellFolder = NULL;
2635 HRESULT hr;
2636
2637 /* Build the display name in the form "::{GUID}". */
2638 if (wcslen (wGuid) >= MAX_PATH)
2639 return E_INVALIDARG;
2640 WCHAR szAdapterGuid[MAX_PATH + 2] = {0};
2641 swprintf (szAdapterGuid, L"::%ls", wGuid);
2642
2643 /* Create an instance of the network connections folder. */
2644 hr = CoCreateInstance (CLSID_NetworkConnections, NULL,
2645 CLSCTX_INPROC_SERVER, IID_IShellFolder,
2646 reinterpret_cast <LPVOID *> (&pShellFolder));
2647 /* Parse the display name. */
2648 if (SUCCEEDED (hr))
2649 {
2650 hr = pShellFolder->ParseDisplayName (NULL, NULL, szAdapterGuid, NULL,
2651 &pidl, NULL);
2652 }
2653 if (SUCCEEDED (hr))
2654 {
2655 hr = pShellFolder->SetNameOf (NULL, pidl, wNewName, SHGDN_NORMAL,
2656 &pidl);
2657 }
2658
2659 CoTaskMemFree (pidl);
2660
2661 if (pShellFolder)
2662 pShellFolder->Release();
2663
2664 return hr;
2665}
2666
2667extern "C" HRESULT RenameConnection (PCWSTR GuidString, PCWSTR NewName)
2668{
2669 typedef HRESULT (WINAPI *lpHrRenameConnection) (const GUID *, PCWSTR);
2670 lpHrRenameConnection RenameConnectionFunc = NULL;
2671 HRESULT status;
2672
2673 /* First try the IShellFolder interface, which was unimplemented
2674 * for the network connections folder before XP. */
2675 status = rename_shellfolder (GuidString, NewName);
2676 if (status == E_NOTIMPL)
2677 {
2678/** @todo that code doesn't seem to work! */
2679 /* The IShellFolder interface is not implemented on this platform.
2680 * Try the (undocumented) HrRenameConnection API in the netshell
2681 * library. */
2682 CLSID clsid;
2683 HINSTANCE hNetShell;
2684 status = CLSIDFromString ((LPOLESTR) GuidString, &clsid);
2685 if (FAILED(status))
2686 return E_FAIL;
2687 hNetShell = LoadLibrary (NETSHELL_LIBRARY);
2688 if (hNetShell == NULL)
2689 return E_FAIL;
2690 RenameConnectionFunc =
2691 (lpHrRenameConnection) GetProcAddress (hNetShell,
2692 "HrRenameConnection");
2693 if (RenameConnectionFunc == NULL)
2694 {
2695 FreeLibrary (hNetShell);
2696 return E_FAIL;
2697 }
2698 status = RenameConnectionFunc (&clsid, NewName);
2699 FreeLibrary (hNetShell);
2700 }
2701 if (FAILED (status))
2702 return status;
2703
2704 return S_OK;
2705}
2706
2707#define DRIVERHWID _T("vboxtap")
2708
2709#define SetErrBreak(strAndArgs) \
2710 if (1) { \
2711 aErrMsg = Utf8StrFmt strAndArgs; vrc = VERR_GENERAL_FAILURE; break; \
2712 } else do {} while (0)
2713
2714/* static */
2715int Host::createNetworkInterface (SVCHlpClient *aClient,
2716 const Utf8Str &aName,
2717 Guid &aGUID, Utf8Str &aErrMsg)
2718{
2719 LogFlowFuncEnter();
2720 LogFlowFunc (("Network connection name = '%s'\n", aName.raw()));
2721
2722 AssertReturn (aClient, VERR_INVALID_POINTER);
2723 AssertReturn (!aName.isNull(), VERR_INVALID_PARAMETER);
2724
2725 int vrc = VINF_SUCCESS;
2726
2727 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
2728 SP_DEVINFO_DATA DeviceInfoData;
2729 DWORD ret = 0;
2730 BOOL found = FALSE;
2731 BOOL registered = FALSE;
2732 BOOL destroyList = FALSE;
2733 TCHAR pCfgGuidString [50];
2734
2735 do
2736 {
2737 BOOL ok;
2738 GUID netGuid;
2739 SP_DRVINFO_DATA DriverInfoData;
2740 SP_DEVINSTALL_PARAMS DeviceInstallParams;
2741 TCHAR className [MAX_PATH];
2742 DWORD index = 0;
2743 PSP_DRVINFO_DETAIL_DATA pDriverInfoDetail;
2744 /* for our purposes, 2k buffer is more
2745 * than enough to obtain the hardware ID
2746 * of the VBoxTAP driver. */
2747 DWORD detailBuf [2048];
2748
2749 HKEY hkey = NULL;
2750 DWORD cbSize;
2751 DWORD dwValueType;
2752
2753 /* initialize the structure size */
2754 DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
2755 DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
2756
2757 /* copy the net class GUID */
2758 memcpy(&netGuid, &GUID_DEVCLASS_NET, sizeof(GUID_DEVCLASS_NET));
2759
2760 /* create an empty device info set associated with the net class GUID */
2761 hDeviceInfo = SetupDiCreateDeviceInfoList (&netGuid, NULL);
2762 if (hDeviceInfo == INVALID_HANDLE_VALUE)
2763 SetErrBreak (("SetupDiCreateDeviceInfoList failed (0x%08X)",
2764 GetLastError()));
2765
2766 /* get the class name from GUID */
2767 ok = SetupDiClassNameFromGuid (&netGuid, className, MAX_PATH, NULL);
2768 if (!ok)
2769 SetErrBreak (("SetupDiClassNameFromGuid failed (0x%08X)",
2770 GetLastError()));
2771
2772 /* create a device info element and add the new device instance
2773 * key to registry */
2774 ok = SetupDiCreateDeviceInfo (hDeviceInfo, className, &netGuid, NULL, NULL,
2775 DICD_GENERATE_ID, &DeviceInfoData);
2776 if (!ok)
2777 SetErrBreak (("SetupDiCreateDeviceInfo failed (0x%08X)",
2778 GetLastError()));
2779
2780 /* select the newly created device info to be the currently
2781 selected member */
2782 ok = SetupDiSetSelectedDevice (hDeviceInfo, &DeviceInfoData);
2783 if (!ok)
2784 SetErrBreak (("SetupDiSetSelectedDevice failed (0x%08X)",
2785 GetLastError()));
2786
2787 /* build a list of class drivers */
2788 ok = SetupDiBuildDriverInfoList (hDeviceInfo, &DeviceInfoData,
2789 SPDIT_CLASSDRIVER);
2790 if (!ok)
2791 SetErrBreak (("SetupDiBuildDriverInfoList failed (0x%08X)",
2792 GetLastError()));
2793
2794 destroyList = TRUE;
2795
2796 /* enumerate the driver info list */
2797 while (TRUE)
2798 {
2799 BOOL ret;
2800
2801 ret = SetupDiEnumDriverInfo (hDeviceInfo, &DeviceInfoData,
2802 SPDIT_CLASSDRIVER, index, &DriverInfoData);
2803
2804 /* if the function failed and GetLastError() returned
2805 * ERROR_NO_MORE_ITEMS, then we have reached the end of the
2806 * list. Othewise there was something wrong with this
2807 * particular driver. */
2808 if (!ret)
2809 {
2810 if(GetLastError() == ERROR_NO_MORE_ITEMS)
2811 break;
2812 else
2813 {
2814 index++;
2815 continue;
2816 }
2817 }
2818
2819 pDriverInfoDetail = (PSP_DRVINFO_DETAIL_DATA) detailBuf;
2820 pDriverInfoDetail->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
2821
2822 /* if we successfully find the hardware ID and it turns out to
2823 * be the one for the loopback driver, then we are done. */
2824 if (SetupDiGetDriverInfoDetail (hDeviceInfo,
2825 &DeviceInfoData,
2826 &DriverInfoData,
2827 pDriverInfoDetail,
2828 sizeof (detailBuf),
2829 NULL))
2830 {
2831 TCHAR * t;
2832
2833 /* pDriverInfoDetail->HardwareID is a MULTISZ string. Go through the
2834 * whole list and see if there is a match somewhere. */
2835 t = pDriverInfoDetail->HardwareID;
2836 while (t && *t && t < (TCHAR *) &detailBuf [sizeof(detailBuf) / sizeof (detailBuf[0])])
2837 {
2838 if (!_tcsicmp(t, DRIVERHWID))
2839 break;
2840
2841 t += _tcslen(t) + 1;
2842 }
2843
2844 if (t && *t && t < (TCHAR *) &detailBuf [sizeof(detailBuf) / sizeof (detailBuf[0])])
2845 {
2846 found = TRUE;
2847 break;
2848 }
2849 }
2850
2851 index ++;
2852 }
2853
2854 if (!found)
2855 SetErrBreak ((tr ("Could not find Host Interface Networking driver! "
2856 "Please reinstall")));
2857
2858 /* set the loopback driver to be the currently selected */
2859 ok = SetupDiSetSelectedDriver (hDeviceInfo, &DeviceInfoData,
2860 &DriverInfoData);
2861 if (!ok)
2862 SetErrBreak (("SetupDiSetSelectedDriver failed (0x%08X)",
2863 GetLastError()));
2864
2865 /* register the phantom device to prepare for install */
2866 ok = SetupDiCallClassInstaller (DIF_REGISTERDEVICE, hDeviceInfo,
2867 &DeviceInfoData);
2868 if (!ok)
2869 SetErrBreak (("SetupDiCallClassInstaller failed (0x%08X)",
2870 GetLastError()));
2871
2872 /* registered, but remove if errors occur in the following code */
2873 registered = TRUE;
2874
2875 /* ask the installer if we can install the device */
2876 ok = SetupDiCallClassInstaller (DIF_ALLOW_INSTALL, hDeviceInfo,
2877 &DeviceInfoData);
2878 if (!ok)
2879 {
2880 if (GetLastError() != ERROR_DI_DO_DEFAULT)
2881 SetErrBreak (("SetupDiCallClassInstaller (DIF_ALLOW_INSTALL) failed (0x%08X)",
2882 GetLastError()));
2883 /* that's fine */
2884 }
2885
2886 /* install the files first */
2887 ok = SetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES, hDeviceInfo,
2888 &DeviceInfoData);
2889 if (!ok)
2890 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES) failed (0x%08X)",
2891 GetLastError()));
2892
2893 /* get the device install parameters and disable filecopy */
2894 DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
2895 ok = SetupDiGetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
2896 &DeviceInstallParams);
2897 if (ok)
2898 {
2899 DeviceInstallParams.Flags |= DI_NOFILECOPY;
2900 ok = SetupDiSetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
2901 &DeviceInstallParams);
2902 if (!ok)
2903 SetErrBreak (("SetupDiSetDeviceInstallParams failed (0x%08X)",
2904 GetLastError()));
2905 }
2906
2907 /*
2908 * Register any device-specific co-installers for this device,
2909 */
2910
2911 ok = SetupDiCallClassInstaller (DIF_REGISTER_COINSTALLERS,
2912 hDeviceInfo,
2913 &DeviceInfoData);
2914 if (!ok)
2915 SetErrBreak (("SetupDiCallClassInstaller (DIF_REGISTER_COINSTALLERS) failed (0x%08X)",
2916 GetLastError()));
2917
2918 /*
2919 * install any installer-specified interfaces.
2920 * and then do the real install
2921 */
2922 ok = SetupDiCallClassInstaller (DIF_INSTALLINTERFACES,
2923 hDeviceInfo,
2924 &DeviceInfoData);
2925 if (!ok)
2926 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLINTERFACES) failed (0x%08X)",
2927 GetLastError()));
2928
2929 ok = SetupDiCallClassInstaller (DIF_INSTALLDEVICE,
2930 hDeviceInfo,
2931 &DeviceInfoData);
2932 if (!ok)
2933 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLDEVICE) failed (0x%08X)",
2934 GetLastError()));
2935
2936 /* Figure out NetCfgInstanceId */
2937 hkey = SetupDiOpenDevRegKey (hDeviceInfo,
2938 &DeviceInfoData,
2939 DICS_FLAG_GLOBAL,
2940 0,
2941 DIREG_DRV,
2942 KEY_READ);
2943 if (hkey == INVALID_HANDLE_VALUE)
2944 SetErrBreak (("SetupDiOpenDevRegKey failed (0x%08X)",
2945 GetLastError()));
2946
2947 cbSize = sizeof (pCfgGuidString);
2948 DWORD ret;
2949 ret = RegQueryValueEx (hkey, _T ("NetCfgInstanceId"), NULL,
2950 &dwValueType, (LPBYTE) pCfgGuidString, &cbSize);
2951 RegCloseKey (hkey);
2952
2953 ret = RenameConnection (pCfgGuidString, Bstr (aName));
2954 if (FAILED (ret))
2955 SetErrBreak (("Failed to set interface name (ret=0x%08X, "
2956 "pCfgGuidString='%ls', cbSize=%d)",
2957 ret, pCfgGuidString, cbSize));
2958 }
2959 while (0);
2960
2961 /*
2962 * cleanup
2963 */
2964
2965 if (hDeviceInfo != INVALID_HANDLE_VALUE)
2966 {
2967 /* an error has occured, but the device is registered, we must remove it */
2968 if (ret != 0 && registered)
2969 SetupDiCallClassInstaller (DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
2970
2971 found = SetupDiDeleteDeviceInfo (hDeviceInfo, &DeviceInfoData);
2972
2973 /* destroy the driver info list */
2974 if (destroyList)
2975 SetupDiDestroyDriverInfoList (hDeviceInfo, &DeviceInfoData,
2976 SPDIT_CLASSDRIVER);
2977 /* clean up the device info set */
2978 SetupDiDestroyDeviceInfoList (hDeviceInfo);
2979 }
2980
2981 /* return the network connection GUID on success */
2982 if (RT_SUCCESS (vrc))
2983 {
2984 /* remove the curly bracket at the end */
2985 pCfgGuidString [_tcslen (pCfgGuidString) - 1] = '\0';
2986 LogFlowFunc (("Network connection GUID string = {%ls}\n", pCfgGuidString + 1));
2987
2988 aGUID = Guid (Utf8Str (pCfgGuidString + 1));
2989 LogFlowFunc (("Network connection GUID = {%RTuuid}\n", aGUID.raw()));
2990 Assert (!aGUID.isEmpty());
2991 }
2992
2993 LogFlowFunc (("vrc=%Rrc\n", vrc));
2994 LogFlowFuncLeave();
2995 return vrc;
2996}
2997
2998/* static */
2999int Host::removeNetworkInterface (SVCHlpClient *aClient,
3000 const Guid &aGUID,
3001 Utf8Str &aErrMsg)
3002{
3003 LogFlowFuncEnter();
3004 LogFlowFunc (("Network connection GUID = {%RTuuid}\n", aGUID.raw()));
3005
3006 AssertReturn (aClient, VERR_INVALID_POINTER);
3007 AssertReturn (!aGUID.isEmpty(), VERR_INVALID_PARAMETER);
3008
3009 int vrc = VINF_SUCCESS;
3010
3011 do
3012 {
3013 TCHAR lszPnPInstanceId [512] = {0};
3014
3015 /* We have to find the device instance ID through a registry search */
3016
3017 HKEY hkeyNetwork = 0;
3018 HKEY hkeyConnection = 0;
3019
3020 do
3021 {
3022 char strRegLocation [256];
3023 sprintf (strRegLocation,
3024 "SYSTEM\\CurrentControlSet\\Control\\Network\\"
3025 "{4D36E972-E325-11CE-BFC1-08002BE10318}\\{%s}",
3026 aGUID.toString().raw());
3027 LONG status;
3028 status = RegOpenKeyExA (HKEY_LOCAL_MACHINE, strRegLocation, 0,
3029 KEY_READ, &hkeyNetwork);
3030 if ((status != ERROR_SUCCESS) || !hkeyNetwork)
3031 SetErrBreak ((
3032 tr ("Host interface network is not found in registry (%s) [1]"),
3033 strRegLocation));
3034
3035 status = RegOpenKeyExA (hkeyNetwork, "Connection", 0,
3036 KEY_READ, &hkeyConnection);
3037 if ((status != ERROR_SUCCESS) || !hkeyConnection)
3038 SetErrBreak ((
3039 tr ("Host interface network is not found in registry (%s) [2]"),
3040 strRegLocation));
3041
3042 DWORD len = sizeof (lszPnPInstanceId);
3043 DWORD dwKeyType;
3044 status = RegQueryValueExW (hkeyConnection, L"PnPInstanceID", NULL,
3045 &dwKeyType, (LPBYTE) lszPnPInstanceId, &len);
3046 if ((status != ERROR_SUCCESS) || (dwKeyType != REG_SZ))
3047 SetErrBreak ((
3048 tr ("Host interface network is not found in registry (%s) [3]"),
3049 strRegLocation));
3050 }
3051 while (0);
3052
3053 if (hkeyConnection)
3054 RegCloseKey (hkeyConnection);
3055 if (hkeyNetwork)
3056 RegCloseKey (hkeyNetwork);
3057
3058 if (RT_FAILURE (vrc))
3059 break;
3060
3061 /*
3062 * Now we are going to enumerate all network devices and
3063 * wait until we encounter the right device instance ID
3064 */
3065
3066 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
3067
3068 do
3069 {
3070 BOOL ok;
3071 DWORD ret = 0;
3072 GUID netGuid;
3073 SP_DEVINFO_DATA DeviceInfoData;
3074 DWORD index = 0;
3075 BOOL found = FALSE;
3076 DWORD size = 0;
3077
3078 /* initialize the structure size */
3079 DeviceInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
3080
3081 /* copy the net class GUID */
3082 memcpy (&netGuid, &GUID_DEVCLASS_NET, sizeof (GUID_DEVCLASS_NET));
3083
3084 /* return a device info set contains all installed devices of the Net class */
3085 hDeviceInfo = SetupDiGetClassDevs (&netGuid, NULL, NULL, DIGCF_PRESENT);
3086
3087 if (hDeviceInfo == INVALID_HANDLE_VALUE)
3088 SetErrBreak (("SetupDiGetClassDevs failed (0x%08X)", GetLastError()));
3089
3090 /* enumerate the driver info list */
3091 while (TRUE)
3092 {
3093 TCHAR *deviceHwid;
3094
3095 ok = SetupDiEnumDeviceInfo (hDeviceInfo, index, &DeviceInfoData);
3096
3097 if (!ok)
3098 {
3099 if (GetLastError() == ERROR_NO_MORE_ITEMS)
3100 break;
3101 else
3102 {
3103 index++;
3104 continue;
3105 }
3106 }
3107
3108 /* try to get the hardware ID registry property */
3109 ok = SetupDiGetDeviceRegistryProperty (hDeviceInfo,
3110 &DeviceInfoData,
3111 SPDRP_HARDWAREID,
3112 NULL,
3113 NULL,
3114 0,
3115 &size);
3116 if (!ok)
3117 {
3118 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3119 {
3120 index++;
3121 continue;
3122 }
3123
3124 deviceHwid = (TCHAR *) malloc (size);
3125 ok = SetupDiGetDeviceRegistryProperty (hDeviceInfo,
3126 &DeviceInfoData,
3127 SPDRP_HARDWAREID,
3128 NULL,
3129 (PBYTE)deviceHwid,
3130 size,
3131 NULL);
3132 if (!ok)
3133 {
3134 free (deviceHwid);
3135 deviceHwid = NULL;
3136 index++;
3137 continue;
3138 }
3139 }
3140 else
3141 {
3142 /* something is wrong. This shouldn't have worked with a NULL buffer */
3143 index++;
3144 continue;
3145 }
3146
3147 for (TCHAR *t = deviceHwid;
3148 t && *t && t < &deviceHwid[size / sizeof(TCHAR)];
3149 t += _tcslen (t) + 1)
3150 {
3151 if (!_tcsicmp (DRIVERHWID, t))
3152 {
3153 /* get the device instance ID */
3154 TCHAR devID [MAX_DEVICE_ID_LEN];
3155 if (CM_Get_Device_ID(DeviceInfoData.DevInst,
3156 devID, MAX_DEVICE_ID_LEN, 0) == CR_SUCCESS)
3157 {
3158 /* compare to what we determined before */
3159 if (wcscmp(devID, lszPnPInstanceId) == 0)
3160 {
3161 found = TRUE;
3162 break;
3163 }
3164 }
3165 }
3166 }
3167
3168 if (deviceHwid)
3169 {
3170 free (deviceHwid);
3171 deviceHwid = NULL;
3172 }
3173
3174 if (found)
3175 break;
3176
3177 index++;
3178 }
3179
3180 if (found == FALSE)
3181 SetErrBreak ((tr ("Host Interface Network driver not found (0x%08X)"),
3182 GetLastError()));
3183
3184 ok = SetupDiSetSelectedDevice (hDeviceInfo, &DeviceInfoData);
3185 if (!ok)
3186 SetErrBreak (("SetupDiSetSelectedDevice failed (0x%08X)",
3187 GetLastError()));
3188
3189 ok = SetupDiCallClassInstaller (DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
3190 if (!ok)
3191 SetErrBreak (("SetupDiCallClassInstaller (DIF_REMOVE) failed (0x%08X)",
3192 GetLastError()));
3193 }
3194 while (0);
3195
3196 /* clean up the device info set */
3197 if (hDeviceInfo != INVALID_HANDLE_VALUE)
3198 SetupDiDestroyDeviceInfoList (hDeviceInfo);
3199
3200 if (RT_FAILURE (vrc))
3201 break;
3202 }
3203 while (0);
3204
3205 LogFlowFunc (("vrc=%Rrc\n", vrc));
3206 LogFlowFuncLeave();
3207 return vrc;
3208}
3209
3210#undef SetErrBreak
3211
3212/* static */
3213HRESULT Host::networkInterfaceHelperClient (SVCHlpClient *aClient,
3214 Progress *aProgress,
3215 void *aUser, int *aVrc)
3216{
3217 LogFlowFuncEnter();
3218 LogFlowFunc (("aClient={%p}, aProgress={%p}, aUser={%p}\n",
3219 aClient, aProgress, aUser));
3220
3221 AssertReturn ((aClient == NULL && aProgress == NULL && aVrc == NULL) ||
3222 (aClient != NULL && aProgress != NULL && aVrc != NULL),
3223 E_POINTER);
3224 AssertReturn (aUser, E_POINTER);
3225
3226 std::auto_ptr <NetworkInterfaceHelperClientData>
3227 d (static_cast <NetworkInterfaceHelperClientData *> (aUser));
3228
3229 if (aClient == NULL)
3230 {
3231 /* "cleanup only" mode, just return (it will free aUser) */
3232 return S_OK;
3233 }
3234
3235 HRESULT rc = S_OK;
3236 int vrc = VINF_SUCCESS;
3237
3238 switch (d->msgCode)
3239 {
3240 case SVCHlpMsg::CreateHostNetworkInterface:
3241 {
3242 LogFlowFunc (("CreateHostNetworkInterface:\n"));
3243 LogFlowFunc (("Network connection name = '%ls'\n", d->name.raw()));
3244
3245 /* write message and parameters */
3246 vrc = aClient->write (d->msgCode);
3247 if (RT_FAILURE (vrc)) break;
3248 vrc = aClient->write (Utf8Str (d->name));
3249 if (RT_FAILURE (vrc)) break;
3250
3251 /* wait for a reply */
3252 bool endLoop = false;
3253 while (!endLoop)
3254 {
3255 SVCHlpMsg::Code reply = SVCHlpMsg::Null;
3256
3257 vrc = aClient->read (reply);
3258 if (RT_FAILURE (vrc)) break;
3259
3260 switch (reply)
3261 {
3262 case SVCHlpMsg::CreateHostNetworkInterface_OK:
3263 {
3264 /* read the GUID */
3265 Guid guid;
3266 vrc = aClient->read (guid);
3267 if (RT_FAILURE (vrc)) break;
3268
3269 LogFlowFunc (("Network connection GUID = {%RTuuid}\n", guid.raw()));
3270
3271 /* initialize the object returned to the caller by
3272 * CreateHostNetworkInterface() */
3273 rc = d->iface->init (d->name, guid);
3274 endLoop = true;
3275 break;
3276 }
3277 case SVCHlpMsg::Error:
3278 {
3279 /* read the error message */
3280 Utf8Str errMsg;
3281 vrc = aClient->read (errMsg);
3282 if (RT_FAILURE (vrc)) break;
3283
3284 rc = setError (E_FAIL, errMsg);
3285 endLoop = true;
3286 break;
3287 }
3288 default:
3289 {
3290 endLoop = true;
3291 ComAssertMsgFailedBreak ((
3292 "Invalid message code %d (%08lX)\n",
3293 reply, reply),
3294 rc = E_FAIL);
3295 }
3296 }
3297 }
3298
3299 break;
3300 }
3301 case SVCHlpMsg::RemoveHostNetworkInterface:
3302 {
3303 LogFlowFunc (("RemoveHostNetworkInterface:\n"));
3304 LogFlowFunc (("Network connection GUID = {%RTuuid}\n", d->guid.raw()));
3305
3306 /* write message and parameters */
3307 vrc = aClient->write (d->msgCode);
3308 if (RT_FAILURE (vrc)) break;
3309 vrc = aClient->write (d->guid);
3310 if (RT_FAILURE (vrc)) break;
3311
3312 /* wait for a reply */
3313 bool endLoop = false;
3314 while (!endLoop)
3315 {
3316 SVCHlpMsg::Code reply = SVCHlpMsg::Null;
3317
3318 vrc = aClient->read (reply);
3319 if (RT_FAILURE (vrc)) break;
3320
3321 switch (reply)
3322 {
3323 case SVCHlpMsg::OK:
3324 {
3325 /* no parameters */
3326 rc = S_OK;
3327 endLoop = true;
3328 break;
3329 }
3330 case SVCHlpMsg::Error:
3331 {
3332 /* read the error message */
3333 Utf8Str errMsg;
3334 vrc = aClient->read (errMsg);
3335 if (RT_FAILURE (vrc)) break;
3336
3337 rc = setError (E_FAIL, errMsg);
3338 endLoop = true;
3339 break;
3340 }
3341 default:
3342 {
3343 endLoop = true;
3344 ComAssertMsgFailedBreak ((
3345 "Invalid message code %d (%08lX)\n",
3346 reply, reply),
3347 rc = E_FAIL);
3348 }
3349 }
3350 }
3351
3352 break;
3353 }
3354 default:
3355 ComAssertMsgFailedBreak ((
3356 "Invalid message code %d (%08lX)\n",
3357 d->msgCode, d->msgCode),
3358 rc = E_FAIL);
3359 }
3360
3361 if (aVrc)
3362 *aVrc = vrc;
3363
3364 LogFlowFunc (("rc=0x%08X, vrc=%Rrc\n", rc, vrc));
3365 LogFlowFuncLeave();
3366 return rc;
3367}
3368
3369/* static */
3370int Host::networkInterfaceHelperServer (SVCHlpClient *aClient,
3371 SVCHlpMsg::Code aMsgCode)
3372{
3373 LogFlowFuncEnter();
3374 LogFlowFunc (("aClient={%p}, aMsgCode=%d\n", aClient, aMsgCode));
3375
3376 AssertReturn (aClient, VERR_INVALID_POINTER);
3377
3378 int vrc = VINF_SUCCESS;
3379
3380 switch (aMsgCode)
3381 {
3382 case SVCHlpMsg::CreateHostNetworkInterface:
3383 {
3384 LogFlowFunc (("CreateHostNetworkInterface:\n"));
3385
3386 Utf8Str name;
3387 vrc = aClient->read (name);
3388 if (RT_FAILURE (vrc)) break;
3389
3390 Guid guid;
3391 Utf8Str errMsg;
3392 vrc = createNetworkInterface (aClient, name, guid, errMsg);
3393
3394 if (RT_SUCCESS (vrc))
3395 {
3396 /* write success followed by GUID */
3397 vrc = aClient->write (SVCHlpMsg::CreateHostNetworkInterface_OK);
3398 if (RT_FAILURE (vrc)) break;
3399 vrc = aClient->write (guid);
3400 if (RT_FAILURE (vrc)) break;
3401 }
3402 else
3403 {
3404 /* write failure followed by error message */
3405 if (errMsg.isEmpty())
3406 errMsg = Utf8StrFmt ("Unspecified error (%Rrc)", vrc);
3407 vrc = aClient->write (SVCHlpMsg::Error);
3408 if (RT_FAILURE (vrc)) break;
3409 vrc = aClient->write (errMsg);
3410 if (RT_FAILURE (vrc)) break;
3411 }
3412
3413 break;
3414 }
3415 case SVCHlpMsg::RemoveHostNetworkInterface:
3416 {
3417 LogFlowFunc (("RemoveHostNetworkInterface:\n"));
3418
3419 Guid guid;
3420 vrc = aClient->read (guid);
3421 if (RT_FAILURE (vrc)) break;
3422
3423 Utf8Str errMsg;
3424 vrc = removeNetworkInterface (aClient, guid, errMsg);
3425
3426 if (RT_SUCCESS (vrc))
3427 {
3428 /* write parameter-less success */
3429 vrc = aClient->write (SVCHlpMsg::OK);
3430 if (RT_FAILURE (vrc)) break;
3431 }
3432 else
3433 {
3434 /* write failure followed by error message */
3435 if (errMsg.isEmpty())
3436 errMsg = Utf8StrFmt ("Unspecified error (%Rrc)", vrc);
3437 vrc = aClient->write (SVCHlpMsg::Error);
3438 if (RT_FAILURE (vrc)) break;
3439 vrc = aClient->write (errMsg);
3440 if (RT_FAILURE (vrc)) break;
3441 }
3442
3443 break;
3444 }
3445 default:
3446 AssertMsgFailedBreakStmt (
3447 ("Invalid message code %d (%08lX)\n", aMsgCode, aMsgCode),
3448 VERR_GENERAL_FAILURE);
3449 }
3450
3451 LogFlowFunc (("vrc=%Rrc\n", vrc));
3452 LogFlowFuncLeave();
3453 return vrc;
3454}
3455
3456#endif /* RT_OS_WINDOWS */
3457
3458#ifdef VBOX_WITH_RESOURCE_USAGE_API
3459void Host::registerMetrics (PerformanceCollector *aCollector)
3460{
3461 pm::CollectorHAL *hal = aCollector->getHAL();
3462 /* Create sub metrics */
3463 pm::SubMetric *cpuLoadUser = new pm::SubMetric ("CPU/Load/User",
3464 "Percentage of processor time spent in user mode.");
3465 pm::SubMetric *cpuLoadKernel = new pm::SubMetric ("CPU/Load/Kernel",
3466 "Percentage of processor time spent in kernel mode.");
3467 pm::SubMetric *cpuLoadIdle = new pm::SubMetric ("CPU/Load/Idle",
3468 "Percentage of processor time spent idling.");
3469 pm::SubMetric *cpuMhzSM = new pm::SubMetric ("CPU/MHz",
3470 "Average of current frequency of all processors.");
3471 pm::SubMetric *ramUsageTotal = new pm::SubMetric ("RAM/Usage/Total",
3472 "Total physical memory installed.");
3473 pm::SubMetric *ramUsageUsed = new pm::SubMetric ("RAM/Usage/Used",
3474 "Physical memory currently occupied.");
3475 pm::SubMetric *ramUsageFree = new pm::SubMetric ("RAM/Usage/Free",
3476 "Physical memory currently available to applications.");
3477 /* Create and register base metrics */
3478 IUnknown *objptr;
3479 ComObjPtr <Host> tmp = this;
3480 tmp.queryInterfaceTo (&objptr);
3481 pm::BaseMetric *cpuLoad = new pm::HostCpuLoadRaw (hal, objptr, cpuLoadUser, cpuLoadKernel,
3482 cpuLoadIdle);
3483 aCollector->registerBaseMetric (cpuLoad);
3484 pm::BaseMetric *cpuMhz = new pm::HostCpuMhz (hal, objptr, cpuMhzSM);
3485 aCollector->registerBaseMetric (cpuMhz);
3486 pm::BaseMetric *ramUsage = new pm::HostRamUsage (hal, objptr, ramUsageTotal, ramUsageUsed,
3487 ramUsageFree);
3488 aCollector->registerBaseMetric (ramUsage);
3489
3490 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadUser, 0));
3491 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadUser,
3492 new pm::AggregateAvg()));
3493 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadUser,
3494 new pm::AggregateMin()));
3495 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadUser,
3496 new pm::AggregateMax()));
3497
3498 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadKernel, 0));
3499 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadKernel,
3500 new pm::AggregateAvg()));
3501 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadKernel,
3502 new pm::AggregateMin()));
3503 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadKernel,
3504 new pm::AggregateMax()));
3505
3506 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadIdle, 0));
3507 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadIdle,
3508 new pm::AggregateAvg()));
3509 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadIdle,
3510 new pm::AggregateMin()));
3511 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadIdle,
3512 new pm::AggregateMax()));
3513
3514 aCollector->registerMetric (new pm::Metric(cpuMhz, cpuMhzSM, 0));
3515 aCollector->registerMetric (new pm::Metric(cpuMhz, cpuMhzSM,
3516 new pm::AggregateAvg()));
3517 aCollector->registerMetric (new pm::Metric(cpuMhz, cpuMhzSM,
3518 new pm::AggregateMin()));
3519 aCollector->registerMetric (new pm::Metric(cpuMhz, cpuMhzSM,
3520 new pm::AggregateMax()));
3521
3522 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageTotal, 0));
3523 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageTotal,
3524 new pm::AggregateAvg()));
3525 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageTotal,
3526 new pm::AggregateMin()));
3527 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageTotal,
3528 new pm::AggregateMax()));
3529
3530 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageUsed, 0));
3531 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageUsed,
3532 new pm::AggregateAvg()));
3533 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageUsed,
3534 new pm::AggregateMin()));
3535 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageUsed,
3536 new pm::AggregateMax()));
3537
3538 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageFree, 0));
3539 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageFree,
3540 new pm::AggregateAvg()));
3541 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageFree,
3542 new pm::AggregateMin()));
3543 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageFree,
3544 new pm::AggregateMax()));
3545};
3546
3547void Host::unregisterMetrics (PerformanceCollector *aCollector)
3548{
3549 aCollector->unregisterMetricsFor (this);
3550 aCollector->unregisterBaseMetricsFor (this);
3551};
3552#endif /* VBOX_WITH_RESOURCE_USAGE_API */
3553/* 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