VirtualBox

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

Last change on this file since 16927 was 16927, checked in by vboxsync, 15 years ago

NetAdp/win: enabled add/remove tap if UI, make the proper adapters to be displayed in the list

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

© 2023 Oracle
ContactPrivacy policyTerms of Use