VirtualBox

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

Last change on this file since 15741 was 15686, checked in by vboxsync, 16 years ago

Reminder to remove obsolete code after we branch.

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

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