VirtualBox

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

Last change on this file since 17389 was 17280, checked in by vboxsync, 16 years ago

Fix burns.

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

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