VirtualBox

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

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

Main: do not include include/VBox/settings.h from other header files but only from implementations that need it (save compile time)

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

© 2023 Oracle
ContactPrivacy policyTerms of Use