VirtualBox

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

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

UI/config part of win NetFlt

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

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