VirtualBox

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

最後變更 在這個檔案從17200是 17200,由 vboxsync 提交於 16 年 前

#3551: “Main: Replace remaining collections with safe arrays”
Take two. Convert HostDVDDriveCollection. This time for all plattforms.

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

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