VirtualBox

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

Last change on this file since 14780 was 14772, checked in by vboxsync, 16 years ago

Added vim modelines to aid following coding guidelines, like no tabs,
similar to what is already in the xidl file.

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