VirtualBox

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

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

Forgot dereferrence.

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

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