VirtualBox

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

Last change on this file since 15091 was 15051, checked in by vboxsync, 16 years ago

Main: Cleaned up the long standing const BSTR = const (OLECHAR *) on WIn32 vs (const PRunichar) * on XPCOM clash. Cleaned up BSTR/GUID macros (IN_BSTR replaces INPTR BSTR, IN_GUID replaces INPTR GUIDPARAM, OUT_GUID replaces GUIDPARAMOUT).

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