VirtualBox

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

Last change on this file since 13659 was 13655, checked in by vboxsync, 17 years ago

Power notification handling added (disabled skeleton).

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

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