VirtualBox

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

Last change on this file since 15246 was 15235, checked in by vboxsync, 16 years ago

#3282: API, RT generic part, updated VBoxManage list hostif.

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