VirtualBox

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

Last change on this file since 14694 was 14685, checked in by vboxsync, 16 years ago

NetFlt/win: fix to 1.host network issue after vm termination 2.hif filtering 3.ms loopback adapter support

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

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