VirtualBox

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

Last change on this file since 17071 was 16967, checked in by vboxsync, 16 years ago

NetAdp: added a Real property to the IHostNetworkInterface, make the interface name be honored in VM settings

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette