VirtualBox

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

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

Main: VirtualBoxBase::addCaller() now returns E_ACCESSDENIED. Also replaced E_UNEXPECTED with E_FAIL in all Assert* statements (for consistency).

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

© 2023 Oracle
ContactPrivacy policyTerms of Use