VirtualBox

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

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

compile fix

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

© 2023 Oracle
ContactPrivacy policyTerms of Use