VirtualBox

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

Last change on this file since 15486 was 15455, checked in by vboxsync, 16 years ago

#3282 HostNetIf API: Solaris implementaion is functional except IP V6 addresses. Fixed erroneous return codes in Host::MemorySize and Host::MemoryAvailable along the way.

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