VirtualBox

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

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

Main/Solaris: Enabled Solaris USB ProxyService now that nspr is resolved.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use