VirtualBox

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

Last change on this file since 15828 was 15752, checked in by vboxsync, 16 years ago

NetFlt/win: don't display disabled adapters

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