VirtualBox

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

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

win NetFlt/Main: fix for adaptor list calculation

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

© 2023 Oracle
ContactPrivacy policyTerms of Use