VirtualBox

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

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

Main: back out r42503

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 118.0 KB
Line 
1/* $Id: HostImpl.cpp 16558 2009-02-06 16:41:43Z 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 ULONG uComponentStatus;
1000 hr = pMpNcc->GetDeviceStatus(&uComponentStatus);
1001 Assert(hr == S_OK);
1002 if(hr == S_OK)
1003 {
1004 if(uComponentStatus == 0)
1005 {
1006 vboxNetWinAddComponent(&list, pMpNcc);
1007 }
1008 }
1009 VBoxNetCfgWinReleaseRef( pMpNcc );
1010 }
1011 VBoxNetCfgWinReleaseRef(pBi);
1012
1013 hr = VBoxNetCfgWinGetNextBindingInterface(pEnumBi, &pBi);
1014 }
1015 VBoxNetCfgWinReleaseRef(pEnumBi);
1016 }
1017 }
1018 VBoxNetCfgWinReleaseRef(pBp);
1019
1020 hr = VBoxNetCfgWinGetNextBindingPath(pEnumBp, &pBp);
1021 }
1022 VBoxNetCfgWinReleaseRef(pEnumBp);
1023 }
1024 VBoxNetCfgWinReleaseRef(pTcpIpNcc);
1025 }
1026 else
1027 {
1028 LogRel(("failed to get the sun_VBoxNetFlt component, error (0x%x)", hr));
1029 }
1030
1031 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE);
1032 }
1033# endif /* # if defined VBOX_WITH_NETFLT */
1034
1035
1036# elif defined RT_OS_LINUX
1037 int sock = socket(AF_INET, SOCK_DGRAM, 0);
1038 if (sock >= 0)
1039 {
1040 char pBuffer[2048];
1041 struct ifconf ifConf;
1042 ifConf.ifc_len = sizeof(pBuffer);
1043 ifConf.ifc_buf = pBuffer;
1044 if (ioctl(sock, SIOCGIFCONF, &ifConf) >= 0)
1045 {
1046 for (struct ifreq *pReq = ifConf.ifc_req; (char*)pReq < pBuffer + ifConf.ifc_len; pReq++)
1047 {
1048 if (ioctl(sock, SIOCGIFHWADDR, pReq) >= 0)
1049 {
1050 if (pReq->ifr_hwaddr.sa_family == ARPHRD_ETHER)
1051 {
1052 RTUUID uuid;
1053 Assert(sizeof(uuid) <= sizeof(*pReq));
1054 memcpy(&uuid, pReq, sizeof(uuid));
1055
1056 ComObjPtr<HostNetworkInterface> IfObj;
1057 IfObj.createObject();
1058 if (SUCCEEDED(IfObj->init(Bstr(pReq->ifr_name), Guid(uuid))))
1059 list.push_back(IfObj);
1060 }
1061 }
1062 }
1063 }
1064 close(sock);
1065 }
1066# endif /* RT_OS_LINUX */
1067#endif
1068 SafeIfaceArray <IHostNetworkInterface> networkInterfaces (list);
1069 networkInterfaces.detachTo (ComSafeArrayOutArg (aNetworkInterfaces));
1070
1071 return S_OK;
1072
1073#else
1074 /* Not implemented / supported on this platform. */
1075 ReturnComNotImplemented();
1076#endif
1077}
1078
1079STDMETHODIMP Host::COMGETTER(USBDevices)(IHostUSBDeviceCollection **aUSBDevices)
1080{
1081#ifdef VBOX_WITH_USB
1082 CheckComArgOutPointerValid(aUSBDevices);
1083
1084 AutoWriteLock alock (this);
1085 CHECK_READY();
1086
1087 MultiResult rc = checkUSBProxyService();
1088 CheckComRCReturnRC (rc);
1089
1090 return mUSBProxyService->getDeviceCollection (aUSBDevices);
1091
1092#else
1093 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1094 * extended error info to indicate that USB is simply not available
1095 * (w/o treating it as a failure), for example, as in OSE. */
1096 ReturnComNotImplemented();
1097#endif
1098}
1099
1100STDMETHODIMP Host::COMGETTER(USBDeviceFilters) (IHostUSBDeviceFilterCollection **aUSBDeviceFilters)
1101{
1102#ifdef VBOX_WITH_USB
1103 CheckComArgOutPointerValid(aUSBDeviceFilters);
1104
1105 AutoWriteLock alock (this);
1106 CHECK_READY();
1107
1108 MultiResult rc = checkUSBProxyService();
1109 CheckComRCReturnRC (rc);
1110
1111 ComObjPtr <HostUSBDeviceFilterCollection> collection;
1112 collection.createObject();
1113 collection->init (mUSBDeviceFilters);
1114 collection.queryInterfaceTo (aUSBDeviceFilters);
1115
1116 return rc;
1117#else
1118 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1119 * extended error info to indicate that USB is simply not available
1120 * (w/o treating it as a failure), for example, as in OSE. */
1121 ReturnComNotImplemented();
1122#endif
1123}
1124
1125/**
1126 * Returns the number of installed logical processors
1127 *
1128 * @returns COM status code
1129 * @param count address of result variable
1130 */
1131STDMETHODIMP Host::COMGETTER(ProcessorCount)(ULONG *aCount)
1132{
1133 CheckComArgOutPointerValid(aCount);
1134 AutoWriteLock alock (this);
1135 CHECK_READY();
1136 *aCount = RTMpGetPresentCount();
1137 return S_OK;
1138}
1139
1140/**
1141 * Returns the number of online logical processors
1142 *
1143 * @returns COM status code
1144 * @param count address of result variable
1145 */
1146STDMETHODIMP Host::COMGETTER(ProcessorOnlineCount)(ULONG *aCount)
1147{
1148 CheckComArgOutPointerValid(aCount);
1149 AutoWriteLock alock (this);
1150 CHECK_READY();
1151 *aCount = RTMpGetOnlineCount();
1152 return S_OK;
1153}
1154
1155/**
1156 * Returns the (approximate) maximum speed of the given host CPU in MHz
1157 *
1158 * @returns COM status code
1159 * @param cpu id to get info for.
1160 * @param speed address of result variable, speed is 0 if unknown or aCpuId is invalid.
1161 */
1162STDMETHODIMP Host::GetProcessorSpeed(ULONG aCpuId, ULONG *aSpeed)
1163{
1164 CheckComArgOutPointerValid(aSpeed);
1165 AutoWriteLock alock (this);
1166 CHECK_READY();
1167 *aSpeed = RTMpGetMaxFrequency(aCpuId);
1168 return S_OK;
1169}
1170/**
1171 * Returns a description string for the host CPU
1172 *
1173 * @returns COM status code
1174 * @param cpu id to get info for.
1175 * @param description address of result variable, NULL if known or aCpuId is invalid.
1176 */
1177STDMETHODIMP Host::GetProcessorDescription(ULONG aCpuId, BSTR *aDescription)
1178{
1179 CheckComArgOutPointerValid(aDescription);
1180 AutoWriteLock alock (this);
1181 CHECK_READY();
1182 /** @todo */
1183 ReturnComNotImplemented();
1184}
1185
1186/**
1187 * Returns whether a host processor feature is supported or not
1188 *
1189 * @returns COM status code
1190 * @param Feature to query.
1191 * @param address of supported bool result variable
1192 */
1193STDMETHODIMP Host::GetProcessorFeature(ProcessorFeature_T aFeature, BOOL *aSupported)
1194{
1195 CheckComArgOutPointerValid(aSupported);
1196 AutoWriteLock alock (this);
1197 CHECK_READY();
1198
1199 switch (aFeature)
1200 {
1201 case ProcessorFeature_HWVirtEx:
1202 *aSupported = fVTxAMDVSupported;
1203 break;
1204
1205 case ProcessorFeature_PAE:
1206 *aSupported = fPAESupported;
1207 break;
1208
1209 case ProcessorFeature_LongMode:
1210 *aSupported = fLongModeSupported;
1211 break;
1212
1213 default:
1214 ReturnComNotImplemented();
1215 }
1216 return S_OK;
1217}
1218
1219/**
1220 * Returns the amount of installed system memory in megabytes
1221 *
1222 * @returns COM status code
1223 * @param size address of result variable
1224 */
1225STDMETHODIMP Host::COMGETTER(MemorySize)(ULONG *aSize)
1226{
1227 CheckComArgOutPointerValid(aSize);
1228 AutoWriteLock alock (this);
1229 CHECK_READY();
1230 /* @todo This is an ugly hack. There must be a function in IPRT for that. */
1231 pm::CollectorHAL *hal = pm::createHAL();
1232 if (!hal)
1233 return E_FAIL;
1234 ULONG tmp;
1235 int rc = hal->getHostMemoryUsage(aSize, &tmp, &tmp);
1236 *aSize /= 1024;
1237 delete hal;
1238 return rc;
1239}
1240
1241/**
1242 * Returns the current system memory free space in megabytes
1243 *
1244 * @returns COM status code
1245 * @param available address of result variable
1246 */
1247STDMETHODIMP Host::COMGETTER(MemoryAvailable)(ULONG *aAvailable)
1248{
1249 CheckComArgOutPointerValid(aAvailable);
1250 AutoWriteLock alock (this);
1251 CHECK_READY();
1252 /* @todo This is an ugly hack. There must be a function in IPRT for that. */
1253 pm::CollectorHAL *hal = pm::createHAL();
1254 if (!hal)
1255 return E_FAIL;
1256 ULONG tmp;
1257 int rc = hal->getHostMemoryUsage(&tmp, &tmp, aAvailable);
1258 *aAvailable /= 1024;
1259 delete hal;
1260 return rc;
1261}
1262
1263/**
1264 * Returns the name string of the host operating system
1265 *
1266 * @returns COM status code
1267 * @param os address of result variable
1268 */
1269STDMETHODIMP Host::COMGETTER(OperatingSystem)(BSTR *aOs)
1270{
1271 CheckComArgOutPointerValid(aOs);
1272 AutoWriteLock alock (this);
1273 CHECK_READY();
1274 /** @todo */
1275 ReturnComNotImplemented();
1276}
1277
1278/**
1279 * Returns the version string of the host operating system
1280 *
1281 * @returns COM status code
1282 * @param os address of result variable
1283 */
1284STDMETHODIMP Host::COMGETTER(OSVersion)(BSTR *aVersion)
1285{
1286 CheckComArgOutPointerValid(aVersion);
1287 AutoWriteLock alock (this);
1288 CHECK_READY();
1289 /** @todo */
1290 ReturnComNotImplemented();
1291}
1292
1293/**
1294 * Returns the current host time in milliseconds since 1970-01-01 UTC.
1295 *
1296 * @returns COM status code
1297 * @param time address of result variable
1298 */
1299STDMETHODIMP Host::COMGETTER(UTCTime)(LONG64 *aUTCTime)
1300{
1301 CheckComArgOutPointerValid(aUTCTime);
1302 AutoWriteLock alock (this);
1303 CHECK_READY();
1304 RTTIMESPEC now;
1305 *aUTCTime = RTTimeSpecGetMilli(RTTimeNow(&now));
1306 return S_OK;
1307}
1308
1309// IHost methods
1310////////////////////////////////////////////////////////////////////////////////
1311
1312#ifdef RT_OS_WINDOWS
1313/** @todo REMOVE. OBSOLETE NOW. */
1314/**
1315 * Returns TRUE if the Windows version is 6.0 or greater (i.e. it's Vista and
1316 * later OSes) and it has the UAC (User Account Control) feature enabled.
1317 */
1318static BOOL IsUACEnabled()
1319{
1320 LONG rc = 0;
1321
1322 OSVERSIONINFOEX info;
1323 ZeroMemory (&info, sizeof (OSVERSIONINFOEX));
1324 info.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
1325 rc = GetVersionEx ((OSVERSIONINFO *) &info);
1326 AssertReturn (rc != 0, FALSE);
1327
1328 LogFlowFunc (("dwMajorVersion=%d, dwMinorVersion=%d\n",
1329 info.dwMajorVersion, info.dwMinorVersion));
1330
1331 /* we are interested only in Vista (and newer versions...). In all
1332 * earlier versions UAC is not present. */
1333 if (info.dwMajorVersion < 6)
1334 return FALSE;
1335
1336 /* the default EnableLUA value is 1 (Enabled) */
1337 DWORD dwEnableLUA = 1;
1338
1339 HKEY hKey;
1340 rc = RegOpenKeyExA (HKEY_LOCAL_MACHINE,
1341 "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
1342 0, KEY_QUERY_VALUE, &hKey);
1343
1344 Assert (rc == ERROR_SUCCESS || rc == ERROR_PATH_NOT_FOUND);
1345 if (rc == ERROR_SUCCESS)
1346 {
1347
1348 DWORD cbEnableLUA = sizeof (dwEnableLUA);
1349 rc = RegQueryValueExA (hKey, "EnableLUA", NULL, NULL,
1350 (LPBYTE) &dwEnableLUA, &cbEnableLUA);
1351
1352 RegCloseKey (hKey);
1353
1354 Assert (rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND);
1355 }
1356
1357 LogFlowFunc (("rc=%d, dwEnableLUA=%d\n", rc, dwEnableLUA));
1358
1359 return dwEnableLUA == 1;
1360}
1361
1362struct NetworkInterfaceHelperClientData
1363{
1364 SVCHlpMsg::Code msgCode;
1365 /* for SVCHlpMsg::CreateHostNetworkInterface */
1366 Bstr name;
1367 ComObjPtr <HostNetworkInterface> iface;
1368 /* for SVCHlpMsg::RemoveHostNetworkInterface */
1369 Guid guid;
1370};
1371
1372STDMETHODIMP
1373Host::CreateHostNetworkInterface (IN_BSTR aName,
1374 IHostNetworkInterface **aHostNetworkInterface,
1375 IProgress **aProgress)
1376{
1377 CheckComArgNotNull(aName);
1378 CheckComArgOutPointerValid(aHostNetworkInterface);
1379 CheckComArgOutPointerValid(aProgress);
1380
1381 AutoWriteLock alock (this);
1382 CHECK_READY();
1383
1384 HRESULT rc = S_OK;
1385
1386 /* first check whether an interface with the given name already exists */
1387 {
1388 ComPtr <IHostNetworkInterface> iface;
1389 if (SUCCEEDED (FindHostNetworkInterfaceByName (aName, iface.asOutParam())))
1390 return setError (E_INVALIDARG,
1391 tr ("Host network interface '%ls' already exists"), aName);
1392 }
1393
1394 /* create a progress object */
1395 ComObjPtr <Progress> progress;
1396 progress.createObject();
1397 rc = progress->init (mParent, static_cast <IHost *> (this),
1398 Bstr (tr ("Creating host network interface")),
1399 FALSE /* aCancelable */);
1400 CheckComRCReturnRC (rc);
1401 progress.queryInterfaceTo (aProgress);
1402
1403 /* create a new uninitialized host interface object */
1404 ComObjPtr <HostNetworkInterface> iface;
1405 iface.createObject();
1406 iface.queryInterfaceTo (aHostNetworkInterface);
1407
1408 /* create the networkInterfaceHelperClient() argument */
1409 std::auto_ptr <NetworkInterfaceHelperClientData>
1410 d (new NetworkInterfaceHelperClientData());
1411 AssertReturn (d.get(), E_OUTOFMEMORY);
1412
1413 d->msgCode = SVCHlpMsg::CreateHostNetworkInterface;
1414 d->name = aName;
1415 d->iface = iface;
1416
1417 rc = mParent->startSVCHelperClient (
1418 IsUACEnabled() == TRUE /* aPrivileged */,
1419 networkInterfaceHelperClient,
1420 static_cast <void *> (d.get()),
1421 progress);
1422
1423 if (SUCCEEDED (rc))
1424 {
1425 /* d is now owned by networkInterfaceHelperClient(), so release it */
1426 d.release();
1427 }
1428
1429 return rc;
1430}
1431
1432STDMETHODIMP
1433Host::RemoveHostNetworkInterface (IN_GUID aId,
1434 IHostNetworkInterface **aHostNetworkInterface,
1435 IProgress **aProgress)
1436{
1437 CheckComArgOutPointerValid(aHostNetworkInterface);
1438 CheckComArgOutPointerValid(aProgress);
1439
1440 AutoWriteLock alock (this);
1441 CHECK_READY();
1442
1443 HRESULT rc = S_OK;
1444
1445 /* first check whether an interface with the given name already exists */
1446 {
1447 ComPtr <IHostNetworkInterface> iface;
1448 if (FAILED (FindHostNetworkInterfaceById (aId, iface.asOutParam())))
1449 return setError (VBOX_E_OBJECT_NOT_FOUND,
1450 tr ("Host network interface with UUID {%RTuuid} does not exist"),
1451 Guid (aId).raw());
1452
1453 /* return the object to be removed to the caller */
1454 iface.queryInterfaceTo (aHostNetworkInterface);
1455 }
1456
1457 /* create a progress object */
1458 ComObjPtr <Progress> progress;
1459 progress.createObject();
1460 rc = progress->init (mParent, static_cast <IHost *> (this),
1461 Bstr (tr ("Removing host network interface")),
1462 FALSE /* aCancelable */);
1463 CheckComRCReturnRC (rc);
1464 progress.queryInterfaceTo (aProgress);
1465
1466 /* create the networkInterfaceHelperClient() argument */
1467 std::auto_ptr <NetworkInterfaceHelperClientData>
1468 d (new NetworkInterfaceHelperClientData());
1469 AssertReturn (d.get(), E_OUTOFMEMORY);
1470
1471 d->msgCode = SVCHlpMsg::RemoveHostNetworkInterface;
1472 d->guid = aId;
1473
1474 rc = mParent->startSVCHelperClient (
1475 IsUACEnabled() == TRUE /* aPrivileged */,
1476 networkInterfaceHelperClient,
1477 static_cast <void *> (d.get()),
1478 progress);
1479
1480 if (SUCCEEDED (rc))
1481 {
1482 /* d is now owned by networkInterfaceHelperClient(), so release it */
1483 d.release();
1484 }
1485
1486 return rc;
1487}
1488
1489#endif /* RT_OS_WINDOWS */
1490
1491STDMETHODIMP Host::CreateUSBDeviceFilter (IN_BSTR aName, IHostUSBDeviceFilter **aFilter)
1492{
1493#ifdef VBOX_WITH_USB
1494 CheckComArgStrNotEmptyOrNull(aName);
1495 CheckComArgOutPointerValid(aFilter);
1496
1497 AutoWriteLock alock (this);
1498 CHECK_READY();
1499
1500 ComObjPtr <HostUSBDeviceFilter> filter;
1501 filter.createObject();
1502 HRESULT rc = filter->init (this, aName);
1503 ComAssertComRCRet (rc, rc);
1504 rc = filter.queryInterfaceTo (aFilter);
1505 AssertComRCReturn (rc, rc);
1506 return S_OK;
1507#else
1508 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1509 * extended error info to indicate that USB is simply not available
1510 * (w/o treating it as a failure), for example, as in OSE. */
1511 ReturnComNotImplemented();
1512#endif
1513}
1514
1515STDMETHODIMP Host::InsertUSBDeviceFilter (ULONG aPosition, IHostUSBDeviceFilter *aFilter)
1516{
1517#ifdef VBOX_WITH_USB
1518 CheckComArgNotNull(aFilter);
1519
1520 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1521 AutoWriteLock alock (this);
1522 CHECK_READY();
1523
1524 MultiResult rc = checkUSBProxyService();
1525 CheckComRCReturnRC (rc);
1526
1527 ComObjPtr <HostUSBDeviceFilter> filter = getDependentChild (aFilter);
1528 if (!filter)
1529 return setError (VBOX_E_INVALID_OBJECT_STATE,
1530 tr ("The given USB device filter is not created within "
1531 "this VirtualBox instance"));
1532
1533 if (filter->mInList)
1534 return setError (E_INVALIDARG,
1535 tr ("The given USB device filter is already in the list"));
1536
1537 /* iterate to the position... */
1538 USBDeviceFilterList::iterator it = mUSBDeviceFilters.begin();
1539 std::advance (it, aPosition);
1540 /* ...and insert */
1541 mUSBDeviceFilters.insert (it, filter);
1542 filter->mInList = true;
1543
1544 /* notify the proxy (only when the filter is active) */
1545 if (mUSBProxyService->isActive() && filter->data().mActive)
1546 {
1547 ComAssertRet (filter->id() == NULL, E_FAIL);
1548 filter->id() = mUSBProxyService->insertFilter (&filter->data().mUSBFilter);
1549 }
1550
1551 /* save the global settings */
1552 alock.unlock();
1553 return rc = mParent->saveSettings();
1554#else
1555 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1556 * extended error info to indicate that USB is simply not available
1557 * (w/o treating it as a failure), for example, as in OSE. */
1558 ReturnComNotImplemented();
1559#endif
1560}
1561
1562STDMETHODIMP Host::RemoveUSBDeviceFilter (ULONG aPosition, IHostUSBDeviceFilter **aFilter)
1563{
1564#ifdef VBOX_WITH_USB
1565 CheckComArgOutPointerValid(aFilter);
1566
1567 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1568 AutoWriteLock alock (this);
1569 CHECK_READY();
1570
1571 MultiResult rc = checkUSBProxyService();
1572 CheckComRCReturnRC (rc);
1573
1574 if (!mUSBDeviceFilters.size())
1575 return setError (E_INVALIDARG,
1576 tr ("The USB device filter list is empty"));
1577
1578 if (aPosition >= mUSBDeviceFilters.size())
1579 return setError (E_INVALIDARG,
1580 tr ("Invalid position: %lu (must be in range [0, %lu])"),
1581 aPosition, mUSBDeviceFilters.size() - 1);
1582
1583 ComObjPtr <HostUSBDeviceFilter> filter;
1584 {
1585 /* iterate to the position... */
1586 USBDeviceFilterList::iterator it = mUSBDeviceFilters.begin();
1587 std::advance (it, aPosition);
1588 /* ...get an element from there... */
1589 filter = *it;
1590 /* ...and remove */
1591 filter->mInList = false;
1592 mUSBDeviceFilters.erase (it);
1593 }
1594
1595 filter.queryInterfaceTo (aFilter);
1596
1597 /* notify the proxy (only when the filter is active) */
1598 if (mUSBProxyService->isActive() && filter->data().mActive)
1599 {
1600 ComAssertRet (filter->id() != NULL, E_FAIL);
1601 mUSBProxyService->removeFilter (filter->id());
1602 filter->id() = NULL;
1603 }
1604
1605 /* save the global settings */
1606 alock.unlock();
1607 return rc = mParent->saveSettings();
1608#else
1609 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1610 * extended error info to indicate that USB is simply not available
1611 * (w/o treating it as a failure), for example, as in OSE. */
1612 ReturnComNotImplemented();
1613#endif
1614}
1615
1616// public methods only for internal purposes
1617////////////////////////////////////////////////////////////////////////////////
1618
1619HRESULT Host::loadSettings (const settings::Key &aGlobal)
1620{
1621 using namespace settings;
1622
1623 AutoWriteLock alock (this);
1624 CHECK_READY();
1625
1626 AssertReturn (!aGlobal.isNull(), E_FAIL);
1627
1628 HRESULT rc = S_OK;
1629
1630#ifdef VBOX_WITH_USB
1631 Key::List filters = aGlobal.key ("USBDeviceFilters").keys ("DeviceFilter");
1632 for (Key::List::const_iterator it = filters.begin();
1633 it != filters.end(); ++ it)
1634 {
1635 Bstr name = (*it).stringValue ("name");
1636 bool active = (*it).value <bool> ("active");
1637
1638 Bstr vendorId = (*it).stringValue ("vendorId");
1639 Bstr productId = (*it).stringValue ("productId");
1640 Bstr revision = (*it).stringValue ("revision");
1641 Bstr manufacturer = (*it).stringValue ("manufacturer");
1642 Bstr product = (*it).stringValue ("product");
1643 Bstr serialNumber = (*it).stringValue ("serialNumber");
1644 Bstr port = (*it).stringValue ("port");
1645
1646 USBDeviceFilterAction_T action;
1647 action = USBDeviceFilterAction_Ignore;
1648 const char *actionStr = (*it).stringValue ("action");
1649 if (strcmp (actionStr, "Ignore") == 0)
1650 action = USBDeviceFilterAction_Ignore;
1651 else
1652 if (strcmp (actionStr, "Hold") == 0)
1653 action = USBDeviceFilterAction_Hold;
1654 else
1655 AssertMsgFailed (("Invalid action: '%s'\n", actionStr));
1656
1657 ComObjPtr <HostUSBDeviceFilter> filterObj;
1658 filterObj.createObject();
1659 rc = filterObj->init (this,
1660 name, active, vendorId, productId, revision,
1661 manufacturer, product, serialNumber, port,
1662 action);
1663 /* error info is set by init() when appropriate */
1664 CheckComRCBreakRC (rc);
1665
1666 mUSBDeviceFilters.push_back (filterObj);
1667 filterObj->mInList = true;
1668
1669 /* notify the proxy (only when the filter is active) */
1670 if (filterObj->data().mActive)
1671 {
1672 HostUSBDeviceFilter *flt = filterObj; /* resolve ambiguity */
1673 flt->id() = mUSBProxyService->insertFilter (&filterObj->data().mUSBFilter);
1674 }
1675 }
1676#endif /* VBOX_WITH_USB */
1677
1678 return rc;
1679}
1680
1681HRESULT Host::saveSettings (settings::Key &aGlobal)
1682{
1683 using namespace settings;
1684
1685 AutoWriteLock alock (this);
1686 CHECK_READY();
1687
1688 ComAssertRet (!aGlobal.isNull(), E_FAIL);
1689
1690#ifdef VBOX_WITH_USB
1691 /* first, delete the entry */
1692 Key filters = aGlobal.findKey ("USBDeviceFilters");
1693 if (!filters.isNull())
1694 filters.zap();
1695 /* then, recreate it */
1696 filters = aGlobal.createKey ("USBDeviceFilters");
1697
1698 USBDeviceFilterList::const_iterator it = mUSBDeviceFilters.begin();
1699 while (it != mUSBDeviceFilters.end())
1700 {
1701 AutoWriteLock filterLock (*it);
1702 const HostUSBDeviceFilter::Data &data = (*it)->data();
1703
1704 Key filter = filters.appendKey ("DeviceFilter");
1705
1706 filter.setValue <Bstr> ("name", data.mName);
1707 filter.setValue <bool> ("active", !!data.mActive);
1708
1709 /* all are optional */
1710 Bstr str;
1711 (*it)->COMGETTER (VendorId) (str.asOutParam());
1712 if (!str.isNull())
1713 filter.setValue <Bstr> ("vendorId", str);
1714
1715 (*it)->COMGETTER (ProductId) (str.asOutParam());
1716 if (!str.isNull())
1717 filter.setValue <Bstr> ("productId", str);
1718
1719 (*it)->COMGETTER (Revision) (str.asOutParam());
1720 if (!str.isNull())
1721 filter.setValue <Bstr> ("revision", str);
1722
1723 (*it)->COMGETTER (Manufacturer) (str.asOutParam());
1724 if (!str.isNull())
1725 filter.setValue <Bstr> ("manufacturer", str);
1726
1727 (*it)->COMGETTER (Product) (str.asOutParam());
1728 if (!str.isNull())
1729 filter.setValue <Bstr> ("product", str);
1730
1731 (*it)->COMGETTER (SerialNumber) (str.asOutParam());
1732 if (!str.isNull())
1733 filter.setValue <Bstr> ("serialNumber", str);
1734
1735 (*it)->COMGETTER (Port) (str.asOutParam());
1736 if (!str.isNull())
1737 filter.setValue <Bstr> ("port", str);
1738
1739 /* action is mandatory */
1740 USBDeviceFilterAction_T action = USBDeviceFilterAction_Null;
1741 (*it)->COMGETTER (Action) (&action);
1742 if (action == USBDeviceFilterAction_Ignore)
1743 filter.setStringValue ("action", "Ignore");
1744 else if (action == USBDeviceFilterAction_Hold)
1745 filter.setStringValue ("action", "Hold");
1746 else
1747 AssertMsgFailed (("Invalid action: %d\n", action));
1748
1749 ++ it;
1750 }
1751#endif /* VBOX_WITH_USB */
1752
1753 return S_OK;
1754}
1755
1756#ifdef VBOX_WITH_USB
1757/**
1758 * Called by setter methods of all USB device filters.
1759 */
1760HRESULT Host::onUSBDeviceFilterChange (HostUSBDeviceFilter *aFilter,
1761 BOOL aActiveChanged /* = FALSE */)
1762{
1763 AutoWriteLock alock (this);
1764 CHECK_READY();
1765
1766 if (aFilter->mInList)
1767 {
1768 if (aActiveChanged)
1769 {
1770 // insert/remove the filter from the proxy
1771 if (aFilter->data().mActive)
1772 {
1773 ComAssertRet (aFilter->id() == NULL, E_FAIL);
1774 aFilter->id() = mUSBProxyService->insertFilter (&aFilter->data().mUSBFilter);
1775 }
1776 else
1777 {
1778 ComAssertRet (aFilter->id() != NULL, E_FAIL);
1779 mUSBProxyService->removeFilter (aFilter->id());
1780 aFilter->id() = NULL;
1781 }
1782 }
1783 else
1784 {
1785 if (aFilter->data().mActive)
1786 {
1787 // update the filter in the proxy
1788 ComAssertRet (aFilter->id() != NULL, E_FAIL);
1789 mUSBProxyService->removeFilter (aFilter->id());
1790 aFilter->id() = mUSBProxyService->insertFilter (&aFilter->data().mUSBFilter);
1791 }
1792 }
1793
1794 // save the global settings... yeah, on every single filter property change
1795 alock.unlock();
1796 return mParent->saveSettings();
1797 }
1798
1799 return S_OK;
1800}
1801
1802
1803/**
1804 * Interface for obtaining a copy of the USBDeviceFilterList,
1805 * used by the USBProxyService.
1806 *
1807 * @param aGlobalFilters Where to put the global filter list copy.
1808 * @param aMachines Where to put the machine vector.
1809 */
1810void Host::getUSBFilters(Host::USBDeviceFilterList *aGlobalFilters, VirtualBox::SessionMachineVector *aMachines)
1811{
1812 AutoWriteLock alock (this);
1813
1814 mParent->getOpenedMachines (*aMachines);
1815 *aGlobalFilters = mUSBDeviceFilters;
1816}
1817
1818#endif /* VBOX_WITH_USB */
1819
1820// private methods
1821////////////////////////////////////////////////////////////////////////////////
1822
1823#if defined(RT_OS_SOLARIS) && defined(VBOX_USE_LIBHAL)
1824/* Solaris hosts, loading libhal at runtime */
1825
1826/**
1827 * Helper function to query the hal subsystem for information about DVD drives attached to the
1828 * system.
1829 *
1830 * @returns true if information was successfully obtained, false otherwise
1831 * @retval list drives found will be attached to this list
1832 */
1833bool Host::getDVDInfoFromHal(std::list <ComObjPtr <HostDVDDrive> > &list)
1834{
1835 bool halSuccess = false;
1836 DBusError dbusError;
1837 if (!gLibHalCheckPresence())
1838 return false;
1839 gDBusErrorInit (&dbusError);
1840 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
1841 if (dbusConnection != 0)
1842 {
1843 LibHalContext *halContext = gLibHalCtxNew();
1844 if (halContext != 0)
1845 {
1846 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
1847 {
1848 if (gLibHalCtxInit(halContext, &dbusError))
1849 {
1850 int numDevices;
1851 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
1852 "storage.drive_type", "cdrom",
1853 &numDevices, &dbusError);
1854 if (halDevices != 0)
1855 {
1856 /* Hal is installed and working, so if no devices are reported, assume
1857 that there are none. */
1858 halSuccess = true;
1859 for (int i = 0; i < numDevices; i++)
1860 {
1861 char *devNode = gLibHalDeviceGetPropertyString(halContext,
1862 halDevices[i], "block.device", &dbusError);
1863#ifdef RT_OS_SOLARIS
1864 /* The CD/DVD ioctls work only for raw device nodes. */
1865 char *tmp = getfullrawname(devNode);
1866 gLibHalFreeString(devNode);
1867 devNode = tmp;
1868#endif
1869 if (devNode != 0)
1870 {
1871// if (validateDevice(devNode, true))
1872// {
1873 Utf8Str description;
1874 char *vendor, *product;
1875 /* We do not check the error here, as this field may
1876 not even exist. */
1877 vendor = gLibHalDeviceGetPropertyString(halContext,
1878 halDevices[i], "info.vendor", 0);
1879 product = gLibHalDeviceGetPropertyString(halContext,
1880 halDevices[i], "info.product", &dbusError);
1881 if ((product != 0 && product[0] != 0))
1882 {
1883 if ((vendor != 0) && (vendor[0] != 0))
1884 {
1885 description = Utf8StrFmt ("%s %s",
1886 vendor, product);
1887 }
1888 else
1889 {
1890 description = product;
1891 }
1892 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
1893 hostDVDDriveObj.createObject();
1894 hostDVDDriveObj->init (Bstr (devNode),
1895 Bstr (halDevices[i]),
1896 Bstr (description));
1897 list.push_back (hostDVDDriveObj);
1898 }
1899 else
1900 {
1901 if (product == 0)
1902 {
1903 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
1904 halDevices[i], dbusError.name, dbusError.message));
1905 gDBusErrorFree(&dbusError);
1906 }
1907 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
1908 hostDVDDriveObj.createObject();
1909 hostDVDDriveObj->init (Bstr (devNode),
1910 Bstr (halDevices[i]));
1911 list.push_back (hostDVDDriveObj);
1912 }
1913 if (vendor != 0)
1914 {
1915 gLibHalFreeString(vendor);
1916 }
1917 if (product != 0)
1918 {
1919 gLibHalFreeString(product);
1920 }
1921// }
1922// else
1923// {
1924// LogRel(("Host::COMGETTER(DVDDrives): failed to validate the block device %s as a DVD drive\n"));
1925// }
1926#ifndef RT_OS_SOLARIS
1927 gLibHalFreeString(devNode);
1928#else
1929 free(devNode);
1930#endif
1931 }
1932 else
1933 {
1934 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
1935 halDevices[i], dbusError.name, dbusError.message));
1936 gDBusErrorFree(&dbusError);
1937 }
1938 }
1939 gLibHalFreeStringArray(halDevices);
1940 }
1941 else
1942 {
1943 LogRel(("Host::COMGETTER(DVDDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1944 gDBusErrorFree(&dbusError);
1945 }
1946 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
1947 {
1948 LogRel(("Host::COMGETTER(DVDDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1949 gDBusErrorFree(&dbusError);
1950 }
1951 }
1952 else
1953 {
1954 LogRel(("Host::COMGETTER(DVDDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1955 gDBusErrorFree(&dbusError);
1956 }
1957 gLibHalCtxFree(halContext);
1958 }
1959 else
1960 {
1961 LogRel(("Host::COMGETTER(DVDDrives): failed to set libhal connection to dbus.\n"));
1962 }
1963 }
1964 else
1965 {
1966 LogRel(("Host::COMGETTER(DVDDrives): failed to get a libhal context - out of memory?\n"));
1967 }
1968 gDBusConnectionUnref(dbusConnection);
1969 }
1970 else
1971 {
1972 LogRel(("Host::COMGETTER(DVDDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1973 gDBusErrorFree(&dbusError);
1974 }
1975 return halSuccess;
1976}
1977
1978
1979/**
1980 * Helper function to query the hal subsystem for information about floppy drives attached to the
1981 * system.
1982 *
1983 * @returns true if information was successfully obtained, false otherwise
1984 * @retval list drives found will be attached to this list
1985 */
1986bool Host::getFloppyInfoFromHal(std::list <ComObjPtr <HostFloppyDrive> > &list)
1987{
1988 bool halSuccess = false;
1989 DBusError dbusError;
1990 if (!gLibHalCheckPresence())
1991 return false;
1992 gDBusErrorInit (&dbusError);
1993 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
1994 if (dbusConnection != 0)
1995 {
1996 LibHalContext *halContext = gLibHalCtxNew();
1997 if (halContext != 0)
1998 {
1999 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
2000 {
2001 if (gLibHalCtxInit(halContext, &dbusError))
2002 {
2003 int numDevices;
2004 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
2005 "storage.drive_type", "floppy",
2006 &numDevices, &dbusError);
2007 if (halDevices != 0)
2008 {
2009 /* Hal is installed and working, so if no devices are reported, assume
2010 that there are none. */
2011 halSuccess = true;
2012 for (int i = 0; i < numDevices; i++)
2013 {
2014 char *driveType = gLibHalDeviceGetPropertyString(halContext,
2015 halDevices[i], "storage.drive_type", 0);
2016 if (driveType != 0)
2017 {
2018 if (strcmp(driveType, "floppy") != 0)
2019 {
2020 gLibHalFreeString(driveType);
2021 continue;
2022 }
2023 gLibHalFreeString(driveType);
2024 }
2025 else
2026 {
2027 /* An error occurred. The attribute "storage.drive_type"
2028 probably didn't exist. */
2029 continue;
2030 }
2031 char *devNode = gLibHalDeviceGetPropertyString(halContext,
2032 halDevices[i], "block.device", &dbusError);
2033 if (devNode != 0)
2034 {
2035// if (validateDevice(devNode, false))
2036// {
2037 Utf8Str description;
2038 char *vendor, *product;
2039 /* We do not check the error here, as this field may
2040 not even exist. */
2041 vendor = gLibHalDeviceGetPropertyString(halContext,
2042 halDevices[i], "info.vendor", 0);
2043 product = gLibHalDeviceGetPropertyString(halContext,
2044 halDevices[i], "info.product", &dbusError);
2045 if ((product != 0) && (product[0] != 0))
2046 {
2047 if ((vendor != 0) && (vendor[0] != 0))
2048 {
2049 description = Utf8StrFmt ("%s %s",
2050 vendor, product);
2051 }
2052 else
2053 {
2054 description = product;
2055 }
2056 ComObjPtr <HostFloppyDrive> hostFloppyDrive;
2057 hostFloppyDrive.createObject();
2058 hostFloppyDrive->init (Bstr (devNode),
2059 Bstr (halDevices[i]),
2060 Bstr (description));
2061 list.push_back (hostFloppyDrive);
2062 }
2063 else
2064 {
2065 if (product == 0)
2066 {
2067 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
2068 halDevices[i], dbusError.name, dbusError.message));
2069 gDBusErrorFree(&dbusError);
2070 }
2071 ComObjPtr <HostFloppyDrive> hostFloppyDrive;
2072 hostFloppyDrive.createObject();
2073 hostFloppyDrive->init (Bstr (devNode),
2074 Bstr (halDevices[i]));
2075 list.push_back (hostFloppyDrive);
2076 }
2077 if (vendor != 0)
2078 {
2079 gLibHalFreeString(vendor);
2080 }
2081 if (product != 0)
2082 {
2083 gLibHalFreeString(product);
2084 }
2085// }
2086// else
2087// {
2088// LogRel(("Host::COMGETTER(FloppyDrives): failed to validate the block device %s as a floppy drive\n"));
2089// }
2090 gLibHalFreeString(devNode);
2091 }
2092 else
2093 {
2094 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
2095 halDevices[i], dbusError.name, dbusError.message));
2096 gDBusErrorFree(&dbusError);
2097 }
2098 }
2099 gLibHalFreeStringArray(halDevices);
2100 }
2101 else
2102 {
2103 LogRel(("Host::COMGETTER(FloppyDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2104 gDBusErrorFree(&dbusError);
2105 }
2106 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
2107 {
2108 LogRel(("Host::COMGETTER(FloppyDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2109 gDBusErrorFree(&dbusError);
2110 }
2111 }
2112 else
2113 {
2114 LogRel(("Host::COMGETTER(FloppyDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2115 gDBusErrorFree(&dbusError);
2116 }
2117 gLibHalCtxFree(halContext);
2118 }
2119 else
2120 {
2121 LogRel(("Host::COMGETTER(FloppyDrives): failed to set libhal connection to dbus.\n"));
2122 }
2123 }
2124 else
2125 {
2126 LogRel(("Host::COMGETTER(FloppyDrives): failed to get a libhal context - out of memory?\n"));
2127 }
2128 gDBusConnectionUnref(dbusConnection);
2129 }
2130 else
2131 {
2132 LogRel(("Host::COMGETTER(FloppyDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2133 gDBusErrorFree(&dbusError);
2134 }
2135 return halSuccess;
2136}
2137#endif /* RT_OS_SOLARIS and VBOX_USE_HAL */
2138
2139#if defined(RT_OS_SOLARIS)
2140
2141/**
2142 * Helper function to parse the given mount file and add found entries
2143 */
2144void Host::parseMountTable(char *mountTable, std::list <ComObjPtr <HostDVDDrive> > &list)
2145{
2146#ifdef RT_OS_LINUX
2147 FILE *mtab = setmntent(mountTable, "r");
2148 if (mtab)
2149 {
2150 struct mntent *mntent;
2151 char *mnt_type;
2152 char *mnt_dev;
2153 char *tmp;
2154 while ((mntent = getmntent(mtab)))
2155 {
2156 mnt_type = (char*)malloc(strlen(mntent->mnt_type) + 1);
2157 mnt_dev = (char*)malloc(strlen(mntent->mnt_fsname) + 1);
2158 strcpy(mnt_type, mntent->mnt_type);
2159 strcpy(mnt_dev, mntent->mnt_fsname);
2160 // supermount fs case
2161 if (strcmp(mnt_type, "supermount") == 0)
2162 {
2163 tmp = strstr(mntent->mnt_opts, "fs=");
2164 if (tmp)
2165 {
2166 free(mnt_type);
2167 mnt_type = strdup(tmp + strlen("fs="));
2168 if (mnt_type)
2169 {
2170 tmp = strchr(mnt_type, ',');
2171 if (tmp)
2172 *tmp = '\0';
2173 }
2174 }
2175 tmp = strstr(mntent->mnt_opts, "dev=");
2176 if (tmp)
2177 {
2178 free(mnt_dev);
2179 mnt_dev = strdup(tmp + strlen("dev="));
2180 if (mnt_dev)
2181 {
2182 tmp = strchr(mnt_dev, ',');
2183 if (tmp)
2184 *tmp = '\0';
2185 }
2186 }
2187 }
2188 // use strstr here to cover things fs types like "udf,iso9660"
2189 if (strstr(mnt_type, "iso9660") == 0)
2190 {
2191 /** @todo check whether we've already got the drive in our list! */
2192 if (validateDevice(mnt_dev, true))
2193 {
2194 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
2195 hostDVDDriveObj.createObject();
2196 hostDVDDriveObj->init (Bstr (mnt_dev));
2197 list.push_back (hostDVDDriveObj);
2198 }
2199 }
2200 free(mnt_dev);
2201 free(mnt_type);
2202 }
2203 endmntent(mtab);
2204 }
2205#else // RT_OS_SOLARIS
2206 FILE *mntFile = fopen(mountTable, "r");
2207 if (mntFile)
2208 {
2209 struct mnttab mntTab;
2210 while (getmntent(mntFile, &mntTab) == 0)
2211 {
2212 char *mountName = strdup(mntTab.mnt_special);
2213 char *mountPoint = strdup(mntTab.mnt_mountp);
2214 char *mountFSType = strdup(mntTab.mnt_fstype);
2215
2216 // skip devices we are not interested in
2217 if ((*mountName && mountName[0] == '/') && // skip 'fake' devices (like -hosts, proc, fd, swap)
2218 (*mountFSType && (strcmp(mountFSType, "devfs") != 0 && // skip devfs (i.e. /devices)
2219 strcmp(mountFSType, "dev") != 0 && // skip dev (i.e. /dev)
2220 strcmp(mountFSType, "lofs") != 0)) && // skip loop-back file-system (lofs)
2221 (*mountPoint && strcmp(mountPoint, "/") != 0)) // skip point '/' (Can CD/DVD be mounted at '/' ???)
2222 {
2223 char *rawDevName = getfullrawname(mountName);
2224 if (validateDevice(rawDevName, true))
2225 {
2226 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
2227 hostDVDDriveObj.createObject();
2228 hostDVDDriveObj->init (Bstr (rawDevName));
2229 list.push_back (hostDVDDriveObj);
2230 }
2231 free(rawDevName);
2232 }
2233
2234 free(mountName);
2235 free(mountPoint);
2236 free(mountFSType);
2237 }
2238
2239 fclose(mntFile);
2240 }
2241#endif
2242}
2243
2244/**
2245 * Helper function to check whether the given device node is a valid drive
2246 */
2247bool Host::validateDevice(const char *deviceNode, bool isCDROM)
2248{
2249 struct stat statInfo;
2250 bool retValue = false;
2251
2252 // sanity check
2253 if (!deviceNode)
2254 {
2255 return false;
2256 }
2257
2258 // first a simple stat() call
2259 if (stat(deviceNode, &statInfo) < 0)
2260 {
2261 return false;
2262 } else
2263 {
2264 if (isCDROM)
2265 {
2266 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2267 {
2268 int fileHandle;
2269 // now try to open the device
2270 fileHandle = open(deviceNode, O_RDONLY | O_NONBLOCK, 0);
2271 if (fileHandle >= 0)
2272 {
2273 cdrom_subchnl cdChannelInfo;
2274 cdChannelInfo.cdsc_format = CDROM_MSF;
2275 // this call will finally reveal the whole truth
2276#ifdef RT_OS_LINUX
2277 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2278 (errno == EIO) || (errno == ENOENT) ||
2279 (errno == EINVAL) || (errno == ENOMEDIUM))
2280#else
2281 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2282 (errno == EIO) || (errno == ENOENT) ||
2283 (errno == EINVAL))
2284#endif
2285 {
2286 retValue = true;
2287 }
2288 close(fileHandle);
2289 }
2290 }
2291 } else
2292 {
2293 // floppy case
2294 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2295 {
2296 /// @todo do some more testing, maybe a nice IOCTL!
2297 retValue = true;
2298 }
2299 }
2300 }
2301 return retValue;
2302}
2303#endif // RT_OS_SOLARIS
2304
2305#ifdef VBOX_WITH_USB
2306/**
2307 * Checks for the presense and status of the USB Proxy Service.
2308 * Returns S_OK when the Proxy is present and OK, VBOX_E_HOST_ERROR (as a
2309 * warning) if the proxy service is not available due to the way the host is
2310 * configured (at present, that means that usbfs and hal/DBus are not
2311 * available on a Linux host) or E_FAIL and a corresponding error message
2312 * otherwise. Intended to be used by methods that rely on the Proxy Service
2313 * availability.
2314 *
2315 * @note This method may return a warning result code. It is recommended to use
2316 * MultiError to store the return value.
2317 *
2318 * @note Locks this object for reading.
2319 */
2320HRESULT Host::checkUSBProxyService()
2321{
2322 AutoWriteLock alock (this);
2323 CHECK_READY();
2324
2325 AssertReturn (mUSBProxyService, E_FAIL);
2326 if (!mUSBProxyService->isActive())
2327 {
2328 /* disable the USB controller completely to avoid assertions if the
2329 * USB proxy service could not start. */
2330
2331 if (mUSBProxyService->getLastError() == VERR_FILE_NOT_FOUND)
2332 return setWarning (E_FAIL,
2333 tr ("Could not load the Host USB Proxy Service (%Rrc). "
2334 "The service might not be installed on the host computer"),
2335 mUSBProxyService->getLastError());
2336 if (mUSBProxyService->getLastError() == VINF_SUCCESS)
2337#ifdef RT_OS_LINUX
2338 return setWarning (VBOX_E_HOST_ERROR,
2339# ifdef VBOX_WITH_DBUS
2340 tr ("The USB Proxy Service could not be started, because neither the USB file system (usbfs) nor the hardware information service (hal) is available")
2341# else
2342 tr ("The USB Proxy Service could not be started, because the USB file system (usbfs) is not available")
2343# endif
2344 );
2345#else /* !RT_OS_LINUX */
2346 return setWarning (E_FAIL,
2347 tr ("The USB Proxy Service has not yet been ported to this host"));
2348#endif /* !RT_OS_LINUX */
2349 return setWarning (E_FAIL,
2350 tr ("Could not load the Host USB Proxy service (%Rrc)"),
2351 mUSBProxyService->getLastError());
2352 }
2353
2354 return S_OK;
2355}
2356#endif /* VBOX_WITH_USB */
2357
2358#ifdef RT_OS_WINDOWS
2359
2360/* The original source of the VBoxTAP adapter creation/destruction code has the following copyright */
2361/*
2362 Copyright 2004 by the Massachusetts Institute of Technology
2363
2364 All rights reserved.
2365
2366 Permission to use, copy, modify, and distribute this software and its
2367 documentation for any purpose and without fee is hereby granted,
2368 provided that the above copyright notice appear in all copies and that
2369 both that copyright notice and this permission notice appear in
2370 supporting documentation, and that the name of the Massachusetts
2371 Institute of Technology (M.I.T.) not be used in advertising or publicity
2372 pertaining to distribution of the software without specific, written
2373 prior permission.
2374
2375 M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2376 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2377 M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2378 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2379 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2380 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2381 SOFTWARE.
2382*/
2383
2384
2385#define NETSHELL_LIBRARY _T("netshell.dll")
2386
2387/**
2388 * Use the IShellFolder API to rename the connection.
2389 */
2390static HRESULT rename_shellfolder (PCWSTR wGuid, PCWSTR wNewName)
2391{
2392 /* This is the GUID for the network connections folder. It is constant.
2393 * {7007ACC7-3202-11D1-AAD2-00805FC1270E} */
2394 const GUID CLSID_NetworkConnections = {
2395 0x7007ACC7, 0x3202, 0x11D1, {
2396 0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E
2397 }
2398 };
2399
2400 LPITEMIDLIST pidl = NULL;
2401 IShellFolder *pShellFolder = NULL;
2402 HRESULT hr;
2403
2404 /* Build the display name in the form "::{GUID}". */
2405 if (wcslen (wGuid) >= MAX_PATH)
2406 return E_INVALIDARG;
2407 WCHAR szAdapterGuid[MAX_PATH + 2] = {0};
2408 swprintf (szAdapterGuid, L"::%ls", wGuid);
2409
2410 /* Create an instance of the network connections folder. */
2411 hr = CoCreateInstance (CLSID_NetworkConnections, NULL,
2412 CLSCTX_INPROC_SERVER, IID_IShellFolder,
2413 reinterpret_cast <LPVOID *> (&pShellFolder));
2414 /* Parse the display name. */
2415 if (SUCCEEDED (hr))
2416 {
2417 hr = pShellFolder->ParseDisplayName (NULL, NULL, szAdapterGuid, NULL,
2418 &pidl, NULL);
2419 }
2420 if (SUCCEEDED (hr))
2421 {
2422 hr = pShellFolder->SetNameOf (NULL, pidl, wNewName, SHGDN_NORMAL,
2423 &pidl);
2424 }
2425
2426 CoTaskMemFree (pidl);
2427
2428 if (pShellFolder)
2429 pShellFolder->Release();
2430
2431 return hr;
2432}
2433
2434extern "C" HRESULT RenameConnection (PCWSTR GuidString, PCWSTR NewName)
2435{
2436 typedef HRESULT (WINAPI *lpHrRenameConnection) (const GUID *, PCWSTR);
2437 lpHrRenameConnection RenameConnectionFunc = NULL;
2438 HRESULT status;
2439
2440 /* First try the IShellFolder interface, which was unimplemented
2441 * for the network connections folder before XP. */
2442 status = rename_shellfolder (GuidString, NewName);
2443 if (status == E_NOTIMPL)
2444 {
2445/** @todo that code doesn't seem to work! */
2446 /* The IShellFolder interface is not implemented on this platform.
2447 * Try the (undocumented) HrRenameConnection API in the netshell
2448 * library. */
2449 CLSID clsid;
2450 HINSTANCE hNetShell;
2451 status = CLSIDFromString ((LPOLESTR) GuidString, &clsid);
2452 if (FAILED(status))
2453 return E_FAIL;
2454 hNetShell = LoadLibrary (NETSHELL_LIBRARY);
2455 if (hNetShell == NULL)
2456 return E_FAIL;
2457 RenameConnectionFunc =
2458 (lpHrRenameConnection) GetProcAddress (hNetShell,
2459 "HrRenameConnection");
2460 if (RenameConnectionFunc == NULL)
2461 {
2462 FreeLibrary (hNetShell);
2463 return E_FAIL;
2464 }
2465 status = RenameConnectionFunc (&clsid, NewName);
2466 FreeLibrary (hNetShell);
2467 }
2468 if (FAILED (status))
2469 return status;
2470
2471 return S_OK;
2472}
2473
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
3321STDMETHODIMP Host::FindHostNetworkInterfaceByName(IN_BSTR name, IHostNetworkInterface **networkInterface)
3322{
3323#ifndef VBOX_WITH_HOSTNETIF_API
3324 return E_NOTIMPL;
3325#else
3326 if (!name)
3327 return E_INVALIDARG;
3328 if (!networkInterface)
3329 return E_POINTER;
3330
3331 *networkInterface = NULL;
3332 ComObjPtr <HostNetworkInterface> found;
3333 std::list <ComObjPtr <HostNetworkInterface> > list;
3334 int rc = NetIfList(list);
3335 if (RT_FAILURE(rc))
3336 {
3337 Log(("Failed to get host network interface list with rc=%Vrc\n", rc));
3338 return E_FAIL;
3339 }
3340 std::list <ComObjPtr <HostNetworkInterface> >::iterator it;
3341 for (it = list.begin(); it != list.end(); ++it)
3342 {
3343 Bstr n;
3344 (*it)->COMGETTER(Name) (n.asOutParam());
3345 if (n == name)
3346 found = *it;
3347 }
3348
3349 if (!found)
3350 return setError (E_INVALIDARG, HostNetworkInterface::tr (
3351 "The host network interface with the given name could not be found"));
3352
3353 return found.queryInterfaceTo (networkInterface);
3354#endif
3355}
3356
3357STDMETHODIMP Host::FindHostNetworkInterfaceById(IN_GUID id, IHostNetworkInterface **networkInterface)
3358{
3359#ifndef VBOX_WITH_HOSTNETIF_API
3360 return E_NOTIMPL;
3361#else
3362 if (Guid(id).isEmpty())
3363 return E_INVALIDARG;
3364 if (!networkInterface)
3365 return E_POINTER;
3366
3367 *networkInterface = NULL;
3368 ComObjPtr <HostNetworkInterface> found;
3369 std::list <ComObjPtr <HostNetworkInterface> > list;
3370 int rc = NetIfList(list);
3371 if (RT_FAILURE(rc))
3372 {
3373 Log(("Failed to get host network interface list with rc=%Vrc\n", rc));
3374 return E_FAIL;
3375 }
3376 std::list <ComObjPtr <HostNetworkInterface> >::iterator it;
3377 for (it = list.begin(); it != list.end(); ++it)
3378 {
3379 Guid g;
3380 (*it)->COMGETTER(Id) (g.asOutParam());
3381 if (g == Guid(id))
3382 found = *it;
3383 }
3384
3385 if (!found)
3386 return setError (E_INVALIDARG, HostNetworkInterface::tr (
3387 "The host network interface with the given GUID could not be found"));
3388
3389 return found.queryInterfaceTo (networkInterface);
3390#endif
3391}
3392
3393/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use