VirtualBox

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

Last change on this file since 17467 was 17394, checked in by vboxsync, 16 years ago

#3551: “Main: Replace remaining collections with safe arrays”
Convert USBDeviceFilterCollection.

  • 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 17394 2009-03-05 12:48:15Z 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) (ComSafeArrayOut (IHostUSBDeviceFilter *, aUSBDeviceFilters))
1097{
1098#ifdef VBOX_WITH_USB
1099 CheckComArgOutSafeArrayPointerValid(aUSBDeviceFilters);
1100
1101 AutoWriteLock alock (this);
1102 CHECK_READY();
1103
1104 MultiResult rc = checkUSBProxyService();
1105 CheckComRCReturnRC (rc);
1106
1107 SafeIfaceArray <IHostUSBDeviceFilter> collection (mUSBDeviceFilters);
1108 collection.detachTo (ComSafeArrayOutArg (aUSBDeviceFilters));
1109
1110 return rc;
1111#else
1112 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1113 * extended error info to indicate that USB is simply not available
1114 * (w/o treating it as a failure), for example, as in OSE. */
1115 ReturnComNotImplemented();
1116#endif
1117}
1118
1119/**
1120 * Returns the number of installed logical processors
1121 *
1122 * @returns COM status code
1123 * @param count address of result variable
1124 */
1125STDMETHODIMP Host::COMGETTER(ProcessorCount)(ULONG *aCount)
1126{
1127 CheckComArgOutPointerValid(aCount);
1128 AutoWriteLock alock (this);
1129 CHECK_READY();
1130 *aCount = RTMpGetPresentCount();
1131 return S_OK;
1132}
1133
1134/**
1135 * Returns the number of online logical processors
1136 *
1137 * @returns COM status code
1138 * @param count address of result variable
1139 */
1140STDMETHODIMP Host::COMGETTER(ProcessorOnlineCount)(ULONG *aCount)
1141{
1142 CheckComArgOutPointerValid(aCount);
1143 AutoWriteLock alock (this);
1144 CHECK_READY();
1145 *aCount = RTMpGetOnlineCount();
1146 return S_OK;
1147}
1148
1149/**
1150 * Returns the (approximate) maximum speed of the given host CPU in MHz
1151 *
1152 * @returns COM status code
1153 * @param cpu id to get info for.
1154 * @param speed address of result variable, speed is 0 if unknown or aCpuId is invalid.
1155 */
1156STDMETHODIMP Host::GetProcessorSpeed(ULONG aCpuId, ULONG *aSpeed)
1157{
1158 CheckComArgOutPointerValid(aSpeed);
1159 AutoWriteLock alock (this);
1160 CHECK_READY();
1161 *aSpeed = RTMpGetMaxFrequency(aCpuId);
1162 return S_OK;
1163}
1164/**
1165 * Returns a description string for the host CPU
1166 *
1167 * @returns COM status code
1168 * @param cpu id to get info for.
1169 * @param description address of result variable, NULL if known or aCpuId is invalid.
1170 */
1171STDMETHODIMP Host::GetProcessorDescription(ULONG aCpuId, BSTR *aDescription)
1172{
1173 CheckComArgOutPointerValid(aDescription);
1174 AutoWriteLock alock (this);
1175 CHECK_READY();
1176 /** @todo */
1177 ReturnComNotImplemented();
1178}
1179
1180/**
1181 * Returns whether a host processor feature is supported or not
1182 *
1183 * @returns COM status code
1184 * @param Feature to query.
1185 * @param address of supported bool result variable
1186 */
1187STDMETHODIMP Host::GetProcessorFeature(ProcessorFeature_T aFeature, BOOL *aSupported)
1188{
1189 CheckComArgOutPointerValid(aSupported);
1190 AutoWriteLock alock (this);
1191 CHECK_READY();
1192
1193 switch (aFeature)
1194 {
1195 case ProcessorFeature_HWVirtEx:
1196 *aSupported = fVTxAMDVSupported;
1197 break;
1198
1199 case ProcessorFeature_PAE:
1200 *aSupported = fPAESupported;
1201 break;
1202
1203 case ProcessorFeature_LongMode:
1204 *aSupported = fLongModeSupported;
1205 break;
1206
1207 default:
1208 ReturnComNotImplemented();
1209 }
1210 return S_OK;
1211}
1212
1213/**
1214 * Returns the amount of installed system memory in megabytes
1215 *
1216 * @returns COM status code
1217 * @param size address of result variable
1218 */
1219STDMETHODIMP Host::COMGETTER(MemorySize)(ULONG *aSize)
1220{
1221 CheckComArgOutPointerValid(aSize);
1222 AutoWriteLock alock (this);
1223 CHECK_READY();
1224 /* @todo This is an ugly hack. There must be a function in IPRT for that. */
1225 pm::CollectorHAL *hal = pm::createHAL();
1226 if (!hal)
1227 return E_FAIL;
1228 ULONG tmp;
1229 int rc = hal->getHostMemoryUsage(aSize, &tmp, &tmp);
1230 *aSize /= 1024;
1231 delete hal;
1232 return rc;
1233}
1234
1235/**
1236 * Returns the current system memory free space in megabytes
1237 *
1238 * @returns COM status code
1239 * @param available address of result variable
1240 */
1241STDMETHODIMP Host::COMGETTER(MemoryAvailable)(ULONG *aAvailable)
1242{
1243 CheckComArgOutPointerValid(aAvailable);
1244 AutoWriteLock alock (this);
1245 CHECK_READY();
1246 /* @todo This is an ugly hack. There must be a function in IPRT for that. */
1247 pm::CollectorHAL *hal = pm::createHAL();
1248 if (!hal)
1249 return E_FAIL;
1250 ULONG tmp;
1251 int rc = hal->getHostMemoryUsage(&tmp, &tmp, aAvailable);
1252 *aAvailable /= 1024;
1253 delete hal;
1254 return rc;
1255}
1256
1257/**
1258 * Returns the name string of the host operating system
1259 *
1260 * @returns COM status code
1261 * @param os address of result variable
1262 */
1263STDMETHODIMP Host::COMGETTER(OperatingSystem)(BSTR *aOs)
1264{
1265 CheckComArgOutPointerValid(aOs);
1266 AutoWriteLock alock (this);
1267 CHECK_READY();
1268 /** @todo */
1269 ReturnComNotImplemented();
1270}
1271
1272/**
1273 * Returns the version string of the host operating system
1274 *
1275 * @returns COM status code
1276 * @param os address of result variable
1277 */
1278STDMETHODIMP Host::COMGETTER(OSVersion)(BSTR *aVersion)
1279{
1280 CheckComArgOutPointerValid(aVersion);
1281 AutoWriteLock alock (this);
1282 CHECK_READY();
1283 /** @todo */
1284 ReturnComNotImplemented();
1285}
1286
1287/**
1288 * Returns the current host time in milliseconds since 1970-01-01 UTC.
1289 *
1290 * @returns COM status code
1291 * @param time address of result variable
1292 */
1293STDMETHODIMP Host::COMGETTER(UTCTime)(LONG64 *aUTCTime)
1294{
1295 CheckComArgOutPointerValid(aUTCTime);
1296 AutoWriteLock alock (this);
1297 CHECK_READY();
1298 RTTIMESPEC now;
1299 *aUTCTime = RTTimeSpecGetMilli(RTTimeNow(&now));
1300 return S_OK;
1301}
1302
1303// IHost methods
1304////////////////////////////////////////////////////////////////////////////////
1305
1306#ifdef RT_OS_WINDOWS
1307/** @todo REMOVE. OBSOLETE NOW. */
1308/**
1309 * Returns TRUE if the Windows version is 6.0 or greater (i.e. it's Vista and
1310 * later OSes) and it has the UAC (User Account Control) feature enabled.
1311 */
1312static BOOL IsUACEnabled()
1313{
1314 LONG rc = 0;
1315
1316 OSVERSIONINFOEX info;
1317 ZeroMemory (&info, sizeof (OSVERSIONINFOEX));
1318 info.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
1319 rc = GetVersionEx ((OSVERSIONINFO *) &info);
1320 AssertReturn (rc != 0, FALSE);
1321
1322 LogFlowFunc (("dwMajorVersion=%d, dwMinorVersion=%d\n",
1323 info.dwMajorVersion, info.dwMinorVersion));
1324
1325 /* we are interested only in Vista (and newer versions...). In all
1326 * earlier versions UAC is not present. */
1327 if (info.dwMajorVersion < 6)
1328 return FALSE;
1329
1330 /* the default EnableLUA value is 1 (Enabled) */
1331 DWORD dwEnableLUA = 1;
1332
1333 HKEY hKey;
1334 rc = RegOpenKeyExA (HKEY_LOCAL_MACHINE,
1335 "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
1336 0, KEY_QUERY_VALUE, &hKey);
1337
1338 Assert (rc == ERROR_SUCCESS || rc == ERROR_PATH_NOT_FOUND);
1339 if (rc == ERROR_SUCCESS)
1340 {
1341
1342 DWORD cbEnableLUA = sizeof (dwEnableLUA);
1343 rc = RegQueryValueExA (hKey, "EnableLUA", NULL, NULL,
1344 (LPBYTE) &dwEnableLUA, &cbEnableLUA);
1345
1346 RegCloseKey (hKey);
1347
1348 Assert (rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND);
1349 }
1350
1351 LogFlowFunc (("rc=%d, dwEnableLUA=%d\n", rc, dwEnableLUA));
1352
1353 return dwEnableLUA == 1;
1354}
1355
1356struct NetworkInterfaceHelperClientData
1357{
1358 SVCHlpMsg::Code msgCode;
1359 /* for SVCHlpMsg::CreateHostOnlyNetworkInterface */
1360 Bstr name;
1361 ComObjPtr <HostNetworkInterface> iface;
1362 /* for SVCHlpMsg::RemoveHostOnlyNetworkInterface */
1363 Guid guid;
1364};
1365
1366STDMETHODIMP
1367Host::CreateHostOnlyNetworkInterface (IN_BSTR aName,
1368 IHostNetworkInterface **aHostNetworkInterface,
1369 IProgress **aProgress)
1370{
1371 CheckComArgNotNull(aName);
1372 CheckComArgOutPointerValid(aHostNetworkInterface);
1373 CheckComArgOutPointerValid(aProgress);
1374
1375 AutoWriteLock alock (this);
1376 CHECK_READY();
1377
1378 HRESULT rc = S_OK;
1379
1380 /* first check whether an interface with the given name already exists */
1381 {
1382 ComPtr <IHostNetworkInterface> iface;
1383 if (SUCCEEDED (FindHostNetworkInterfaceByName (aName, iface.asOutParam())))
1384 return setError (E_INVALIDARG,
1385 tr ("Host network interface '%ls' already exists"), aName);
1386 }
1387
1388 /* create a progress object */
1389 ComObjPtr <Progress> progress;
1390 progress.createObject();
1391 rc = progress->init (mParent, static_cast <IHost *> (this),
1392 Bstr (tr ("Creating host network interface")),
1393 FALSE /* aCancelable */);
1394 CheckComRCReturnRC (rc);
1395 progress.queryInterfaceTo (aProgress);
1396
1397 /* create a new uninitialized host interface object */
1398 ComObjPtr <HostNetworkInterface> iface;
1399 iface.createObject();
1400 iface.queryInterfaceTo (aHostNetworkInterface);
1401
1402 /* create the networkInterfaceHelperClient() argument */
1403 std::auto_ptr <NetworkInterfaceHelperClientData>
1404 d (new NetworkInterfaceHelperClientData());
1405 AssertReturn (d.get(), E_OUTOFMEMORY);
1406
1407 d->msgCode = SVCHlpMsg::CreateHostOnlyNetworkInterface;
1408 d->name = aName;
1409 d->iface = iface;
1410
1411 rc = mParent->startSVCHelperClient (
1412 IsUACEnabled() == TRUE /* aPrivileged */,
1413 networkInterfaceHelperClient,
1414 static_cast <void *> (d.get()),
1415 progress);
1416
1417 if (SUCCEEDED (rc))
1418 {
1419 /* d is now owned by networkInterfaceHelperClient(), so release it */
1420 d.release();
1421 }
1422
1423 return rc;
1424}
1425
1426STDMETHODIMP
1427Host::RemoveHostOnlyNetworkInterface (IN_GUID aId,
1428 IHostNetworkInterface **aHostNetworkInterface,
1429 IProgress **aProgress)
1430{
1431 CheckComArgOutPointerValid(aHostNetworkInterface);
1432 CheckComArgOutPointerValid(aProgress);
1433
1434 AutoWriteLock alock (this);
1435 CHECK_READY();
1436
1437 HRESULT rc = S_OK;
1438
1439 /* first check whether an interface with the given name already exists */
1440 {
1441 ComPtr <IHostNetworkInterface> iface;
1442 if (FAILED (FindHostNetworkInterfaceById (aId, iface.asOutParam())))
1443 return setError (VBOX_E_OBJECT_NOT_FOUND,
1444 tr ("Host network interface with UUID {%RTuuid} does not exist"),
1445 Guid (aId).raw());
1446
1447 /* return the object to be removed to the caller */
1448 iface.queryInterfaceTo (aHostNetworkInterface);
1449 }
1450
1451 /* create a progress object */
1452 ComObjPtr <Progress> progress;
1453 progress.createObject();
1454 rc = progress->init (mParent, static_cast <IHost *> (this),
1455 Bstr (tr ("Removing host network interface")),
1456 FALSE /* aCancelable */);
1457 CheckComRCReturnRC (rc);
1458 progress.queryInterfaceTo (aProgress);
1459
1460 /* create the networkInterfaceHelperClient() argument */
1461 std::auto_ptr <NetworkInterfaceHelperClientData>
1462 d (new NetworkInterfaceHelperClientData());
1463 AssertReturn (d.get(), E_OUTOFMEMORY);
1464
1465 d->msgCode = SVCHlpMsg::RemoveHostOnlyNetworkInterface;
1466 d->guid = aId;
1467
1468 rc = mParent->startSVCHelperClient (
1469 IsUACEnabled() == TRUE /* aPrivileged */,
1470 networkInterfaceHelperClient,
1471 static_cast <void *> (d.get()),
1472 progress);
1473
1474 if (SUCCEEDED (rc))
1475 {
1476 /* d is now owned by networkInterfaceHelperClient(), so release it */
1477 d.release();
1478 }
1479
1480 return rc;
1481}
1482
1483#endif /* RT_OS_WINDOWS */
1484
1485STDMETHODIMP Host::CreateUSBDeviceFilter (IN_BSTR aName, IHostUSBDeviceFilter **aFilter)
1486{
1487#ifdef VBOX_WITH_USB
1488 CheckComArgStrNotEmptyOrNull(aName);
1489 CheckComArgOutPointerValid(aFilter);
1490
1491 AutoWriteLock alock (this);
1492 CHECK_READY();
1493
1494 ComObjPtr <HostUSBDeviceFilter> filter;
1495 filter.createObject();
1496 HRESULT rc = filter->init (this, aName);
1497 ComAssertComRCRet (rc, rc);
1498 rc = filter.queryInterfaceTo (aFilter);
1499 AssertComRCReturn (rc, rc);
1500 return S_OK;
1501#else
1502 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1503 * extended error info to indicate that USB is simply not available
1504 * (w/o treating it as a failure), for example, as in OSE. */
1505 ReturnComNotImplemented();
1506#endif
1507}
1508
1509STDMETHODIMP Host::InsertUSBDeviceFilter (ULONG aPosition, IHostUSBDeviceFilter *aFilter)
1510{
1511#ifdef VBOX_WITH_USB
1512 CheckComArgNotNull(aFilter);
1513
1514 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1515 AutoWriteLock alock (this);
1516 CHECK_READY();
1517
1518 MultiResult rc = checkUSBProxyService();
1519 CheckComRCReturnRC (rc);
1520
1521 ComObjPtr <HostUSBDeviceFilter> filter = getDependentChild (aFilter);
1522 if (!filter)
1523 return setError (VBOX_E_INVALID_OBJECT_STATE,
1524 tr ("The given USB device filter is not created within "
1525 "this VirtualBox instance"));
1526
1527 if (filter->mInList)
1528 return setError (E_INVALIDARG,
1529 tr ("The given USB device filter is already in the list"));
1530
1531 /* iterate to the position... */
1532 USBDeviceFilterList::iterator it = mUSBDeviceFilters.begin();
1533 std::advance (it, aPosition);
1534 /* ...and insert */
1535 mUSBDeviceFilters.insert (it, filter);
1536 filter->mInList = true;
1537
1538 /* notify the proxy (only when the filter is active) */
1539 if (mUSBProxyService->isActive() && filter->data().mActive)
1540 {
1541 ComAssertRet (filter->id() == NULL, E_FAIL);
1542 filter->id() = mUSBProxyService->insertFilter (&filter->data().mUSBFilter);
1543 }
1544
1545 /* save the global settings */
1546 alock.unlock();
1547 return rc = mParent->saveSettings();
1548#else
1549 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1550 * extended error info to indicate that USB is simply not available
1551 * (w/o treating it as a failure), for example, as in OSE. */
1552 ReturnComNotImplemented();
1553#endif
1554}
1555
1556STDMETHODIMP Host::RemoveUSBDeviceFilter (ULONG aPosition, IHostUSBDeviceFilter **aFilter)
1557{
1558#ifdef VBOX_WITH_USB
1559 CheckComArgOutPointerValid(aFilter);
1560
1561 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1562 AutoWriteLock alock (this);
1563 CHECK_READY();
1564
1565 MultiResult rc = checkUSBProxyService();
1566 CheckComRCReturnRC (rc);
1567
1568 if (!mUSBDeviceFilters.size())
1569 return setError (E_INVALIDARG,
1570 tr ("The USB device filter list is empty"));
1571
1572 if (aPosition >= mUSBDeviceFilters.size())
1573 return setError (E_INVALIDARG,
1574 tr ("Invalid position: %lu (must be in range [0, %lu])"),
1575 aPosition, mUSBDeviceFilters.size() - 1);
1576
1577 ComObjPtr <HostUSBDeviceFilter> filter;
1578 {
1579 /* iterate to the position... */
1580 USBDeviceFilterList::iterator it = mUSBDeviceFilters.begin();
1581 std::advance (it, aPosition);
1582 /* ...get an element from there... */
1583 filter = *it;
1584 /* ...and remove */
1585 filter->mInList = false;
1586 mUSBDeviceFilters.erase (it);
1587 }
1588
1589 filter.queryInterfaceTo (aFilter);
1590
1591 /* notify the proxy (only when the filter is active) */
1592 if (mUSBProxyService->isActive() && filter->data().mActive)
1593 {
1594 ComAssertRet (filter->id() != NULL, E_FAIL);
1595 mUSBProxyService->removeFilter (filter->id());
1596 filter->id() = NULL;
1597 }
1598
1599 /* save the global settings */
1600 alock.unlock();
1601 return rc = mParent->saveSettings();
1602#else
1603 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1604 * extended error info to indicate that USB is simply not available
1605 * (w/o treating it as a failure), for example, as in OSE. */
1606 ReturnComNotImplemented();
1607#endif
1608}
1609
1610// public methods only for internal purposes
1611////////////////////////////////////////////////////////////////////////////////
1612
1613HRESULT Host::loadSettings (const settings::Key &aGlobal)
1614{
1615 using namespace settings;
1616
1617 AutoWriteLock alock (this);
1618 CHECK_READY();
1619
1620 AssertReturn (!aGlobal.isNull(), E_FAIL);
1621
1622 HRESULT rc = S_OK;
1623
1624#ifdef VBOX_WITH_USB
1625 Key::List filters = aGlobal.key ("USBDeviceFilters").keys ("DeviceFilter");
1626 for (Key::List::const_iterator it = filters.begin();
1627 it != filters.end(); ++ it)
1628 {
1629 Bstr name = (*it).stringValue ("name");
1630 bool active = (*it).value <bool> ("active");
1631
1632 Bstr vendorId = (*it).stringValue ("vendorId");
1633 Bstr productId = (*it).stringValue ("productId");
1634 Bstr revision = (*it).stringValue ("revision");
1635 Bstr manufacturer = (*it).stringValue ("manufacturer");
1636 Bstr product = (*it).stringValue ("product");
1637 Bstr serialNumber = (*it).stringValue ("serialNumber");
1638 Bstr port = (*it).stringValue ("port");
1639
1640 USBDeviceFilterAction_T action;
1641 action = USBDeviceFilterAction_Ignore;
1642 const char *actionStr = (*it).stringValue ("action");
1643 if (strcmp (actionStr, "Ignore") == 0)
1644 action = USBDeviceFilterAction_Ignore;
1645 else
1646 if (strcmp (actionStr, "Hold") == 0)
1647 action = USBDeviceFilterAction_Hold;
1648 else
1649 AssertMsgFailed (("Invalid action: '%s'\n", actionStr));
1650
1651 ComObjPtr <HostUSBDeviceFilter> filterObj;
1652 filterObj.createObject();
1653 rc = filterObj->init (this,
1654 name, active, vendorId, productId, revision,
1655 manufacturer, product, serialNumber, port,
1656 action);
1657 /* error info is set by init() when appropriate */
1658 CheckComRCBreakRC (rc);
1659
1660 mUSBDeviceFilters.push_back (filterObj);
1661 filterObj->mInList = true;
1662
1663 /* notify the proxy (only when the filter is active) */
1664 if (filterObj->data().mActive)
1665 {
1666 HostUSBDeviceFilter *flt = filterObj; /* resolve ambiguity */
1667 flt->id() = mUSBProxyService->insertFilter (&filterObj->data().mUSBFilter);
1668 }
1669 }
1670#endif /* VBOX_WITH_USB */
1671
1672 return rc;
1673}
1674
1675HRESULT Host::saveSettings (settings::Key &aGlobal)
1676{
1677 using namespace settings;
1678
1679 AutoWriteLock alock (this);
1680 CHECK_READY();
1681
1682 ComAssertRet (!aGlobal.isNull(), E_FAIL);
1683
1684#ifdef VBOX_WITH_USB
1685 /* first, delete the entry */
1686 Key filters = aGlobal.findKey ("USBDeviceFilters");
1687 if (!filters.isNull())
1688 filters.zap();
1689 /* then, recreate it */
1690 filters = aGlobal.createKey ("USBDeviceFilters");
1691
1692 USBDeviceFilterList::const_iterator it = mUSBDeviceFilters.begin();
1693 while (it != mUSBDeviceFilters.end())
1694 {
1695 AutoWriteLock filterLock (*it);
1696 const HostUSBDeviceFilter::Data &data = (*it)->data();
1697
1698 Key filter = filters.appendKey ("DeviceFilter");
1699
1700 filter.setValue <Bstr> ("name", data.mName);
1701 filter.setValue <bool> ("active", !!data.mActive);
1702
1703 /* all are optional */
1704 Bstr str;
1705 (*it)->COMGETTER (VendorId) (str.asOutParam());
1706 if (!str.isNull())
1707 filter.setValue <Bstr> ("vendorId", str);
1708
1709 (*it)->COMGETTER (ProductId) (str.asOutParam());
1710 if (!str.isNull())
1711 filter.setValue <Bstr> ("productId", str);
1712
1713 (*it)->COMGETTER (Revision) (str.asOutParam());
1714 if (!str.isNull())
1715 filter.setValue <Bstr> ("revision", str);
1716
1717 (*it)->COMGETTER (Manufacturer) (str.asOutParam());
1718 if (!str.isNull())
1719 filter.setValue <Bstr> ("manufacturer", str);
1720
1721 (*it)->COMGETTER (Product) (str.asOutParam());
1722 if (!str.isNull())
1723 filter.setValue <Bstr> ("product", str);
1724
1725 (*it)->COMGETTER (SerialNumber) (str.asOutParam());
1726 if (!str.isNull())
1727 filter.setValue <Bstr> ("serialNumber", str);
1728
1729 (*it)->COMGETTER (Port) (str.asOutParam());
1730 if (!str.isNull())
1731 filter.setValue <Bstr> ("port", str);
1732
1733 /* action is mandatory */
1734 USBDeviceFilterAction_T action = USBDeviceFilterAction_Null;
1735 (*it)->COMGETTER (Action) (&action);
1736 if (action == USBDeviceFilterAction_Ignore)
1737 filter.setStringValue ("action", "Ignore");
1738 else if (action == USBDeviceFilterAction_Hold)
1739 filter.setStringValue ("action", "Hold");
1740 else
1741 AssertMsgFailed (("Invalid action: %d\n", action));
1742
1743 ++ it;
1744 }
1745#endif /* VBOX_WITH_USB */
1746
1747 return S_OK;
1748}
1749
1750#ifdef VBOX_WITH_USB
1751/**
1752 * Called by setter methods of all USB device filters.
1753 */
1754HRESULT Host::onUSBDeviceFilterChange (HostUSBDeviceFilter *aFilter,
1755 BOOL aActiveChanged /* = FALSE */)
1756{
1757 AutoWriteLock alock (this);
1758 CHECK_READY();
1759
1760 if (aFilter->mInList)
1761 {
1762 if (aActiveChanged)
1763 {
1764 // insert/remove the filter from the proxy
1765 if (aFilter->data().mActive)
1766 {
1767 ComAssertRet (aFilter->id() == NULL, E_FAIL);
1768 aFilter->id() = mUSBProxyService->insertFilter (&aFilter->data().mUSBFilter);
1769 }
1770 else
1771 {
1772 ComAssertRet (aFilter->id() != NULL, E_FAIL);
1773 mUSBProxyService->removeFilter (aFilter->id());
1774 aFilter->id() = NULL;
1775 }
1776 }
1777 else
1778 {
1779 if (aFilter->data().mActive)
1780 {
1781 // update the filter in the proxy
1782 ComAssertRet (aFilter->id() != NULL, E_FAIL);
1783 mUSBProxyService->removeFilter (aFilter->id());
1784 aFilter->id() = mUSBProxyService->insertFilter (&aFilter->data().mUSBFilter);
1785 }
1786 }
1787
1788 // save the global settings... yeah, on every single filter property change
1789 alock.unlock();
1790 return mParent->saveSettings();
1791 }
1792
1793 return S_OK;
1794}
1795
1796
1797/**
1798 * Interface for obtaining a copy of the USBDeviceFilterList,
1799 * used by the USBProxyService.
1800 *
1801 * @param aGlobalFilters Where to put the global filter list copy.
1802 * @param aMachines Where to put the machine vector.
1803 */
1804void Host::getUSBFilters(Host::USBDeviceFilterList *aGlobalFilters, VirtualBox::SessionMachineVector *aMachines)
1805{
1806 AutoWriteLock alock (this);
1807
1808 mParent->getOpenedMachines (*aMachines);
1809 *aGlobalFilters = mUSBDeviceFilters;
1810}
1811
1812#endif /* VBOX_WITH_USB */
1813
1814// private methods
1815////////////////////////////////////////////////////////////////////////////////
1816
1817#if defined(RT_OS_SOLARIS) && defined(VBOX_USE_LIBHAL)
1818/* Solaris hosts, loading libhal at runtime */
1819
1820/**
1821 * Helper function to query the hal subsystem for information about DVD drives attached to the
1822 * system.
1823 *
1824 * @returns true if information was successfully obtained, false otherwise
1825 * @retval list drives found will be attached to this list
1826 */
1827bool Host::getDVDInfoFromHal(std::list <ComObjPtr <HostDVDDrive> > &list)
1828{
1829 bool halSuccess = false;
1830 DBusError dbusError;
1831 if (!gLibHalCheckPresence())
1832 return false;
1833 gDBusErrorInit (&dbusError);
1834 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
1835 if (dbusConnection != 0)
1836 {
1837 LibHalContext *halContext = gLibHalCtxNew();
1838 if (halContext != 0)
1839 {
1840 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
1841 {
1842 if (gLibHalCtxInit(halContext, &dbusError))
1843 {
1844 int numDevices;
1845 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
1846 "storage.drive_type", "cdrom",
1847 &numDevices, &dbusError);
1848 if (halDevices != 0)
1849 {
1850 /* Hal is installed and working, so if no devices are reported, assume
1851 that there are none. */
1852 halSuccess = true;
1853 for (int i = 0; i < numDevices; i++)
1854 {
1855 char *devNode = gLibHalDeviceGetPropertyString(halContext,
1856 halDevices[i], "block.device", &dbusError);
1857#ifdef RT_OS_SOLARIS
1858 /* The CD/DVD ioctls work only for raw device nodes. */
1859 char *tmp = getfullrawname(devNode);
1860 gLibHalFreeString(devNode);
1861 devNode = tmp;
1862#endif
1863 if (devNode != 0)
1864 {
1865// if (validateDevice(devNode, true))
1866// {
1867 Utf8Str description;
1868 char *vendor, *product;
1869 /* We do not check the error here, as this field may
1870 not even exist. */
1871 vendor = gLibHalDeviceGetPropertyString(halContext,
1872 halDevices[i], "info.vendor", 0);
1873 product = gLibHalDeviceGetPropertyString(halContext,
1874 halDevices[i], "info.product", &dbusError);
1875 if ((product != 0 && product[0] != 0))
1876 {
1877 if ((vendor != 0) && (vendor[0] != 0))
1878 {
1879 description = Utf8StrFmt ("%s %s",
1880 vendor, product);
1881 }
1882 else
1883 {
1884 description = product;
1885 }
1886 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
1887 hostDVDDriveObj.createObject();
1888 hostDVDDriveObj->init (Bstr (devNode),
1889 Bstr (halDevices[i]),
1890 Bstr (description));
1891 list.push_back (hostDVDDriveObj);
1892 }
1893 else
1894 {
1895 if (product == 0)
1896 {
1897 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
1898 halDevices[i], dbusError.name, dbusError.message));
1899 gDBusErrorFree(&dbusError);
1900 }
1901 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
1902 hostDVDDriveObj.createObject();
1903 hostDVDDriveObj->init (Bstr (devNode),
1904 Bstr (halDevices[i]));
1905 list.push_back (hostDVDDriveObj);
1906 }
1907 if (vendor != 0)
1908 {
1909 gLibHalFreeString(vendor);
1910 }
1911 if (product != 0)
1912 {
1913 gLibHalFreeString(product);
1914 }
1915// }
1916// else
1917// {
1918// LogRel(("Host::COMGETTER(DVDDrives): failed to validate the block device %s as a DVD drive\n"));
1919// }
1920#ifndef RT_OS_SOLARIS
1921 gLibHalFreeString(devNode);
1922#else
1923 free(devNode);
1924#endif
1925 }
1926 else
1927 {
1928 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
1929 halDevices[i], dbusError.name, dbusError.message));
1930 gDBusErrorFree(&dbusError);
1931 }
1932 }
1933 gLibHalFreeStringArray(halDevices);
1934 }
1935 else
1936 {
1937 LogRel(("Host::COMGETTER(DVDDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1938 gDBusErrorFree(&dbusError);
1939 }
1940 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
1941 {
1942 LogRel(("Host::COMGETTER(DVDDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1943 gDBusErrorFree(&dbusError);
1944 }
1945 }
1946 else
1947 {
1948 LogRel(("Host::COMGETTER(DVDDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1949 gDBusErrorFree(&dbusError);
1950 }
1951 gLibHalCtxFree(halContext);
1952 }
1953 else
1954 {
1955 LogRel(("Host::COMGETTER(DVDDrives): failed to set libhal connection to dbus.\n"));
1956 }
1957 }
1958 else
1959 {
1960 LogRel(("Host::COMGETTER(DVDDrives): failed to get a libhal context - out of memory?\n"));
1961 }
1962 gDBusConnectionUnref(dbusConnection);
1963 }
1964 else
1965 {
1966 LogRel(("Host::COMGETTER(DVDDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1967 gDBusErrorFree(&dbusError);
1968 }
1969 return halSuccess;
1970}
1971
1972
1973/**
1974 * Helper function to query the hal subsystem for information about floppy drives attached to the
1975 * system.
1976 *
1977 * @returns true if information was successfully obtained, false otherwise
1978 * @retval list drives found will be attached to this list
1979 */
1980bool Host::getFloppyInfoFromHal(std::list <ComObjPtr <HostFloppyDrive> > &list)
1981{
1982 bool halSuccess = false;
1983 DBusError dbusError;
1984 if (!gLibHalCheckPresence())
1985 return false;
1986 gDBusErrorInit (&dbusError);
1987 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
1988 if (dbusConnection != 0)
1989 {
1990 LibHalContext *halContext = gLibHalCtxNew();
1991 if (halContext != 0)
1992 {
1993 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
1994 {
1995 if (gLibHalCtxInit(halContext, &dbusError))
1996 {
1997 int numDevices;
1998 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
1999 "storage.drive_type", "floppy",
2000 &numDevices, &dbusError);
2001 if (halDevices != 0)
2002 {
2003 /* Hal is installed and working, so if no devices are reported, assume
2004 that there are none. */
2005 halSuccess = true;
2006 for (int i = 0; i < numDevices; i++)
2007 {
2008 char *driveType = gLibHalDeviceGetPropertyString(halContext,
2009 halDevices[i], "storage.drive_type", 0);
2010 if (driveType != 0)
2011 {
2012 if (strcmp(driveType, "floppy") != 0)
2013 {
2014 gLibHalFreeString(driveType);
2015 continue;
2016 }
2017 gLibHalFreeString(driveType);
2018 }
2019 else
2020 {
2021 /* An error occurred. The attribute "storage.drive_type"
2022 probably didn't exist. */
2023 continue;
2024 }
2025 char *devNode = gLibHalDeviceGetPropertyString(halContext,
2026 halDevices[i], "block.device", &dbusError);
2027 if (devNode != 0)
2028 {
2029// if (validateDevice(devNode, false))
2030// {
2031 Utf8Str description;
2032 char *vendor, *product;
2033 /* We do not check the error here, as this field may
2034 not even exist. */
2035 vendor = gLibHalDeviceGetPropertyString(halContext,
2036 halDevices[i], "info.vendor", 0);
2037 product = gLibHalDeviceGetPropertyString(halContext,
2038 halDevices[i], "info.product", &dbusError);
2039 if ((product != 0) && (product[0] != 0))
2040 {
2041 if ((vendor != 0) && (vendor[0] != 0))
2042 {
2043 description = Utf8StrFmt ("%s %s",
2044 vendor, product);
2045 }
2046 else
2047 {
2048 description = product;
2049 }
2050 ComObjPtr <HostFloppyDrive> hostFloppyDrive;
2051 hostFloppyDrive.createObject();
2052 hostFloppyDrive->init (Bstr (devNode),
2053 Bstr (halDevices[i]),
2054 Bstr (description));
2055 list.push_back (hostFloppyDrive);
2056 }
2057 else
2058 {
2059 if (product == 0)
2060 {
2061 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
2062 halDevices[i], dbusError.name, dbusError.message));
2063 gDBusErrorFree(&dbusError);
2064 }
2065 ComObjPtr <HostFloppyDrive> hostFloppyDrive;
2066 hostFloppyDrive.createObject();
2067 hostFloppyDrive->init (Bstr (devNode),
2068 Bstr (halDevices[i]));
2069 list.push_back (hostFloppyDrive);
2070 }
2071 if (vendor != 0)
2072 {
2073 gLibHalFreeString(vendor);
2074 }
2075 if (product != 0)
2076 {
2077 gLibHalFreeString(product);
2078 }
2079// }
2080// else
2081// {
2082// LogRel(("Host::COMGETTER(FloppyDrives): failed to validate the block device %s as a floppy drive\n"));
2083// }
2084 gLibHalFreeString(devNode);
2085 }
2086 else
2087 {
2088 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
2089 halDevices[i], dbusError.name, dbusError.message));
2090 gDBusErrorFree(&dbusError);
2091 }
2092 }
2093 gLibHalFreeStringArray(halDevices);
2094 }
2095 else
2096 {
2097 LogRel(("Host::COMGETTER(FloppyDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2098 gDBusErrorFree(&dbusError);
2099 }
2100 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
2101 {
2102 LogRel(("Host::COMGETTER(FloppyDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2103 gDBusErrorFree(&dbusError);
2104 }
2105 }
2106 else
2107 {
2108 LogRel(("Host::COMGETTER(FloppyDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2109 gDBusErrorFree(&dbusError);
2110 }
2111 gLibHalCtxFree(halContext);
2112 }
2113 else
2114 {
2115 LogRel(("Host::COMGETTER(FloppyDrives): failed to set libhal connection to dbus.\n"));
2116 }
2117 }
2118 else
2119 {
2120 LogRel(("Host::COMGETTER(FloppyDrives): failed to get a libhal context - out of memory?\n"));
2121 }
2122 gDBusConnectionUnref(dbusConnection);
2123 }
2124 else
2125 {
2126 LogRel(("Host::COMGETTER(FloppyDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2127 gDBusErrorFree(&dbusError);
2128 }
2129 return halSuccess;
2130}
2131#endif /* RT_OS_SOLARIS and VBOX_USE_HAL */
2132
2133#if defined(RT_OS_SOLARIS)
2134
2135/**
2136 * Helper function to parse the given mount file and add found entries
2137 */
2138void Host::parseMountTable(char *mountTable, std::list <ComObjPtr <HostDVDDrive> > &list)
2139{
2140#ifdef RT_OS_LINUX
2141 FILE *mtab = setmntent(mountTable, "r");
2142 if (mtab)
2143 {
2144 struct mntent *mntent;
2145 char *mnt_type;
2146 char *mnt_dev;
2147 char *tmp;
2148 while ((mntent = getmntent(mtab)))
2149 {
2150 mnt_type = (char*)malloc(strlen(mntent->mnt_type) + 1);
2151 mnt_dev = (char*)malloc(strlen(mntent->mnt_fsname) + 1);
2152 strcpy(mnt_type, mntent->mnt_type);
2153 strcpy(mnt_dev, mntent->mnt_fsname);
2154 // supermount fs case
2155 if (strcmp(mnt_type, "supermount") == 0)
2156 {
2157 tmp = strstr(mntent->mnt_opts, "fs=");
2158 if (tmp)
2159 {
2160 free(mnt_type);
2161 mnt_type = strdup(tmp + strlen("fs="));
2162 if (mnt_type)
2163 {
2164 tmp = strchr(mnt_type, ',');
2165 if (tmp)
2166 *tmp = '\0';
2167 }
2168 }
2169 tmp = strstr(mntent->mnt_opts, "dev=");
2170 if (tmp)
2171 {
2172 free(mnt_dev);
2173 mnt_dev = strdup(tmp + strlen("dev="));
2174 if (mnt_dev)
2175 {
2176 tmp = strchr(mnt_dev, ',');
2177 if (tmp)
2178 *tmp = '\0';
2179 }
2180 }
2181 }
2182 // use strstr here to cover things fs types like "udf,iso9660"
2183 if (strstr(mnt_type, "iso9660") == 0)
2184 {
2185 /** @todo check whether we've already got the drive in our list! */
2186 if (validateDevice(mnt_dev, true))
2187 {
2188 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
2189 hostDVDDriveObj.createObject();
2190 hostDVDDriveObj->init (Bstr (mnt_dev));
2191 list.push_back (hostDVDDriveObj);
2192 }
2193 }
2194 free(mnt_dev);
2195 free(mnt_type);
2196 }
2197 endmntent(mtab);
2198 }
2199#else // RT_OS_SOLARIS
2200 FILE *mntFile = fopen(mountTable, "r");
2201 if (mntFile)
2202 {
2203 struct mnttab mntTab;
2204 while (getmntent(mntFile, &mntTab) == 0)
2205 {
2206 char *mountName = strdup(mntTab.mnt_special);
2207 char *mountPoint = strdup(mntTab.mnt_mountp);
2208 char *mountFSType = strdup(mntTab.mnt_fstype);
2209
2210 // skip devices we are not interested in
2211 if ((*mountName && mountName[0] == '/') && // skip 'fake' devices (like -hosts, proc, fd, swap)
2212 (*mountFSType && (strcmp(mountFSType, "devfs") != 0 && // skip devfs (i.e. /devices)
2213 strcmp(mountFSType, "dev") != 0 && // skip dev (i.e. /dev)
2214 strcmp(mountFSType, "lofs") != 0)) && // skip loop-back file-system (lofs)
2215 (*mountPoint && strcmp(mountPoint, "/") != 0)) // skip point '/' (Can CD/DVD be mounted at '/' ???)
2216 {
2217 char *rawDevName = getfullrawname(mountName);
2218 if (validateDevice(rawDevName, true))
2219 {
2220 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
2221 hostDVDDriveObj.createObject();
2222 hostDVDDriveObj->init (Bstr (rawDevName));
2223 list.push_back (hostDVDDriveObj);
2224 }
2225 free(rawDevName);
2226 }
2227
2228 free(mountName);
2229 free(mountPoint);
2230 free(mountFSType);
2231 }
2232
2233 fclose(mntFile);
2234 }
2235#endif
2236}
2237
2238/**
2239 * Helper function to check whether the given device node is a valid drive
2240 */
2241bool Host::validateDevice(const char *deviceNode, bool isCDROM)
2242{
2243 struct stat statInfo;
2244 bool retValue = false;
2245
2246 // sanity check
2247 if (!deviceNode)
2248 {
2249 return false;
2250 }
2251
2252 // first a simple stat() call
2253 if (stat(deviceNode, &statInfo) < 0)
2254 {
2255 return false;
2256 } else
2257 {
2258 if (isCDROM)
2259 {
2260 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2261 {
2262 int fileHandle;
2263 // now try to open the device
2264 fileHandle = open(deviceNode, O_RDONLY | O_NONBLOCK, 0);
2265 if (fileHandle >= 0)
2266 {
2267 cdrom_subchnl cdChannelInfo;
2268 cdChannelInfo.cdsc_format = CDROM_MSF;
2269 // this call will finally reveal the whole truth
2270#ifdef RT_OS_LINUX
2271 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2272 (errno == EIO) || (errno == ENOENT) ||
2273 (errno == EINVAL) || (errno == ENOMEDIUM))
2274#else
2275 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2276 (errno == EIO) || (errno == ENOENT) ||
2277 (errno == EINVAL))
2278#endif
2279 {
2280 retValue = true;
2281 }
2282 close(fileHandle);
2283 }
2284 }
2285 } else
2286 {
2287 // floppy case
2288 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2289 {
2290 /// @todo do some more testing, maybe a nice IOCTL!
2291 retValue = true;
2292 }
2293 }
2294 }
2295 return retValue;
2296}
2297#endif // RT_OS_SOLARIS
2298
2299#ifdef VBOX_WITH_USB
2300/**
2301 * Checks for the presense and status of the USB Proxy Service.
2302 * Returns S_OK when the Proxy is present and OK, VBOX_E_HOST_ERROR (as a
2303 * warning) if the proxy service is not available due to the way the host is
2304 * configured (at present, that means that usbfs and hal/DBus are not
2305 * available on a Linux host) or E_FAIL and a corresponding error message
2306 * otherwise. Intended to be used by methods that rely on the Proxy Service
2307 * availability.
2308 *
2309 * @note This method may return a warning result code. It is recommended to use
2310 * MultiError to store the return value.
2311 *
2312 * @note Locks this object for reading.
2313 */
2314HRESULT Host::checkUSBProxyService()
2315{
2316 AutoWriteLock alock (this);
2317 CHECK_READY();
2318
2319 AssertReturn (mUSBProxyService, E_FAIL);
2320 if (!mUSBProxyService->isActive())
2321 {
2322 /* disable the USB controller completely to avoid assertions if the
2323 * USB proxy service could not start. */
2324
2325 if (mUSBProxyService->getLastError() == VERR_FILE_NOT_FOUND)
2326 return setWarning (E_FAIL,
2327 tr ("Could not load the Host USB Proxy Service (%Rrc). "
2328 "The service might not be installed on the host computer"),
2329 mUSBProxyService->getLastError());
2330 if (mUSBProxyService->getLastError() == VINF_SUCCESS)
2331#ifdef RT_OS_LINUX
2332 return setWarning (VBOX_E_HOST_ERROR,
2333# ifdef VBOX_WITH_DBUS
2334 tr ("The USB Proxy Service could not be started, because neither the USB file system (usbfs) nor the hardware information service (hal) is available")
2335# else
2336 tr ("The USB Proxy Service could not be started, because the USB file system (usbfs) is not available")
2337# endif
2338 );
2339#else /* !RT_OS_LINUX */
2340 return setWarning (E_FAIL,
2341 tr ("The USB Proxy Service has not yet been ported to this host"));
2342#endif /* !RT_OS_LINUX */
2343 return setWarning (E_FAIL,
2344 tr ("Could not load the Host USB Proxy service (%Rrc)"),
2345 mUSBProxyService->getLastError());
2346 }
2347
2348 return S_OK;
2349}
2350#endif /* VBOX_WITH_USB */
2351
2352#ifdef RT_OS_WINDOWS
2353
2354/* The original source of the VBoxTAP adapter creation/destruction code has the following copyright */
2355/*
2356 Copyright 2004 by the Massachusetts Institute of Technology
2357
2358 All rights reserved.
2359
2360 Permission to use, copy, modify, and distribute this software and its
2361 documentation for any purpose and without fee is hereby granted,
2362 provided that the above copyright notice appear in all copies and that
2363 both that copyright notice and this permission notice appear in
2364 supporting documentation, and that the name of the Massachusetts
2365 Institute of Technology (M.I.T.) not be used in advertising or publicity
2366 pertaining to distribution of the software without specific, written
2367 prior permission.
2368
2369 M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2370 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2371 M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2372 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2373 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2374 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2375 SOFTWARE.
2376*/
2377
2378
2379#define NETSHELL_LIBRARY _T("netshell.dll")
2380
2381/**
2382 * Use the IShellFolder API to rename the connection.
2383 */
2384static HRESULT rename_shellfolder (PCWSTR wGuid, PCWSTR wNewName)
2385{
2386 /* This is the GUID for the network connections folder. It is constant.
2387 * {7007ACC7-3202-11D1-AAD2-00805FC1270E} */
2388 const GUID CLSID_NetworkConnections = {
2389 0x7007ACC7, 0x3202, 0x11D1, {
2390 0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E
2391 }
2392 };
2393
2394 LPITEMIDLIST pidl = NULL;
2395 IShellFolder *pShellFolder = NULL;
2396 HRESULT hr;
2397
2398 /* Build the display name in the form "::{GUID}". */
2399 if (wcslen (wGuid) >= MAX_PATH)
2400 return E_INVALIDARG;
2401 WCHAR szAdapterGuid[MAX_PATH + 2] = {0};
2402 swprintf (szAdapterGuid, L"::%ls", wGuid);
2403
2404 /* Create an instance of the network connections folder. */
2405 hr = CoCreateInstance (CLSID_NetworkConnections, NULL,
2406 CLSCTX_INPROC_SERVER, IID_IShellFolder,
2407 reinterpret_cast <LPVOID *> (&pShellFolder));
2408 /* Parse the display name. */
2409 if (SUCCEEDED (hr))
2410 {
2411 hr = pShellFolder->ParseDisplayName (NULL, NULL, szAdapterGuid, NULL,
2412 &pidl, NULL);
2413 }
2414 if (SUCCEEDED (hr))
2415 {
2416 hr = pShellFolder->SetNameOf (NULL, pidl, wNewName, SHGDN_NORMAL,
2417 &pidl);
2418 }
2419
2420 CoTaskMemFree (pidl);
2421
2422 if (pShellFolder)
2423 pShellFolder->Release();
2424
2425 return hr;
2426}
2427
2428extern "C" HRESULT RenameConnection (PCWSTR GuidString, PCWSTR NewName)
2429{
2430 typedef HRESULT (WINAPI *lpHrRenameConnection) (const GUID *, PCWSTR);
2431 lpHrRenameConnection RenameConnectionFunc = NULL;
2432 HRESULT status;
2433
2434 /* First try the IShellFolder interface, which was unimplemented
2435 * for the network connections folder before XP. */
2436 status = rename_shellfolder (GuidString, NewName);
2437 if (status == E_NOTIMPL)
2438 {
2439/** @todo that code doesn't seem to work! */
2440 /* The IShellFolder interface is not implemented on this platform.
2441 * Try the (undocumented) HrRenameConnection API in the netshell
2442 * library. */
2443 CLSID clsid;
2444 HINSTANCE hNetShell;
2445 status = CLSIDFromString ((LPOLESTR) GuidString, &clsid);
2446 if (FAILED(status))
2447 return E_FAIL;
2448 hNetShell = LoadLibrary (NETSHELL_LIBRARY);
2449 if (hNetShell == NULL)
2450 return E_FAIL;
2451 RenameConnectionFunc =
2452 (lpHrRenameConnection) GetProcAddress (hNetShell,
2453 "HrRenameConnection");
2454 if (RenameConnectionFunc == NULL)
2455 {
2456 FreeLibrary (hNetShell);
2457 return E_FAIL;
2458 }
2459 status = RenameConnectionFunc (&clsid, NewName);
2460 FreeLibrary (hNetShell);
2461 }
2462 if (FAILED (status))
2463 return status;
2464
2465 return S_OK;
2466}
2467#ifdef VBOX_WITH_NETFLT
2468# define DRIVERHWID _T("sun_VBoxNetAdp")
2469#else
2470# define DRIVERHWID _T("vboxtap")
2471#endif
2472
2473
2474#define SetErrBreak(strAndArgs) \
2475 if (1) { \
2476 aErrMsg = Utf8StrFmt strAndArgs; vrc = VERR_GENERAL_FAILURE; break; \
2477 } else do {} while (0)
2478
2479/* static */
2480int Host::createNetworkInterface (SVCHlpClient *aClient,
2481 const Utf8Str &aName,
2482 Guid &aGUID, Utf8Str &aErrMsg)
2483{
2484 LogFlowFuncEnter();
2485 LogFlowFunc (("Network connection name = '%s'\n", aName.raw()));
2486
2487 AssertReturn (aClient, VERR_INVALID_POINTER);
2488 AssertReturn (!aName.isNull(), VERR_INVALID_PARAMETER);
2489
2490 int vrc = VINF_SUCCESS;
2491
2492 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
2493 SP_DEVINFO_DATA DeviceInfoData;
2494 DWORD ret = 0;
2495 BOOL found = FALSE;
2496 BOOL registered = FALSE;
2497 BOOL destroyList = FALSE;
2498 TCHAR pCfgGuidString [50];
2499
2500 do
2501 {
2502 BOOL ok;
2503 GUID netGuid;
2504 SP_DRVINFO_DATA DriverInfoData;
2505 SP_DEVINSTALL_PARAMS DeviceInstallParams;
2506 TCHAR className [MAX_PATH];
2507 DWORD index = 0;
2508 PSP_DRVINFO_DETAIL_DATA pDriverInfoDetail;
2509 /* for our purposes, 2k buffer is more
2510 * than enough to obtain the hardware ID
2511 * of the VBoxTAP driver. */
2512 DWORD detailBuf [2048];
2513
2514 HKEY hkey = NULL;
2515 DWORD cbSize;
2516 DWORD dwValueType;
2517
2518 /* initialize the structure size */
2519 DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
2520 DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
2521
2522 /* copy the net class GUID */
2523 memcpy(&netGuid, &GUID_DEVCLASS_NET, sizeof(GUID_DEVCLASS_NET));
2524
2525 /* create an empty device info set associated with the net class GUID */
2526 hDeviceInfo = SetupDiCreateDeviceInfoList (&netGuid, NULL);
2527 if (hDeviceInfo == INVALID_HANDLE_VALUE)
2528 SetErrBreak (("SetupDiCreateDeviceInfoList failed (0x%08X)",
2529 GetLastError()));
2530
2531 /* get the class name from GUID */
2532 ok = SetupDiClassNameFromGuid (&netGuid, className, MAX_PATH, NULL);
2533 if (!ok)
2534 SetErrBreak (("SetupDiClassNameFromGuid failed (0x%08X)",
2535 GetLastError()));
2536
2537 /* create a device info element and add the new device instance
2538 * key to registry */
2539 ok = SetupDiCreateDeviceInfo (hDeviceInfo, className, &netGuid, NULL, NULL,
2540 DICD_GENERATE_ID, &DeviceInfoData);
2541 if (!ok)
2542 SetErrBreak (("SetupDiCreateDeviceInfo failed (0x%08X)",
2543 GetLastError()));
2544
2545 /* select the newly created device info to be the currently
2546 selected member */
2547 ok = SetupDiSetSelectedDevice (hDeviceInfo, &DeviceInfoData);
2548 if (!ok)
2549 SetErrBreak (("SetupDiSetSelectedDevice failed (0x%08X)",
2550 GetLastError()));
2551
2552 /* build a list of class drivers */
2553 ok = SetupDiBuildDriverInfoList (hDeviceInfo, &DeviceInfoData,
2554 SPDIT_CLASSDRIVER);
2555 if (!ok)
2556 SetErrBreak (("SetupDiBuildDriverInfoList failed (0x%08X)",
2557 GetLastError()));
2558
2559 destroyList = TRUE;
2560
2561 /* enumerate the driver info list */
2562 while (TRUE)
2563 {
2564 BOOL ret;
2565
2566 ret = SetupDiEnumDriverInfo (hDeviceInfo, &DeviceInfoData,
2567 SPDIT_CLASSDRIVER, index, &DriverInfoData);
2568
2569 /* if the function failed and GetLastError() returned
2570 * ERROR_NO_MORE_ITEMS, then we have reached the end of the
2571 * list. Othewise there was something wrong with this
2572 * particular driver. */
2573 if (!ret)
2574 {
2575 if(GetLastError() == ERROR_NO_MORE_ITEMS)
2576 break;
2577 else
2578 {
2579 index++;
2580 continue;
2581 }
2582 }
2583
2584 pDriverInfoDetail = (PSP_DRVINFO_DETAIL_DATA) detailBuf;
2585 pDriverInfoDetail->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
2586
2587 /* if we successfully find the hardware ID and it turns out to
2588 * be the one for the loopback driver, then we are done. */
2589 if (SetupDiGetDriverInfoDetail (hDeviceInfo,
2590 &DeviceInfoData,
2591 &DriverInfoData,
2592 pDriverInfoDetail,
2593 sizeof (detailBuf),
2594 NULL))
2595 {
2596 TCHAR * t;
2597
2598 /* pDriverInfoDetail->HardwareID is a MULTISZ string. Go through the
2599 * whole list and see if there is a match somewhere. */
2600 t = pDriverInfoDetail->HardwareID;
2601 while (t && *t && t < (TCHAR *) &detailBuf [sizeof(detailBuf) / sizeof (detailBuf[0])])
2602 {
2603 if (!_tcsicmp(t, DRIVERHWID))
2604 break;
2605
2606 t += _tcslen(t) + 1;
2607 }
2608
2609 if (t && *t && t < (TCHAR *) &detailBuf [sizeof(detailBuf) / sizeof (detailBuf[0])])
2610 {
2611 found = TRUE;
2612 break;
2613 }
2614 }
2615
2616 index ++;
2617 }
2618
2619 if (!found)
2620 SetErrBreak ((tr ("Could not find Host Interface Networking driver! "
2621 "Please reinstall")));
2622
2623 /* set the loopback driver to be the currently selected */
2624 ok = SetupDiSetSelectedDriver (hDeviceInfo, &DeviceInfoData,
2625 &DriverInfoData);
2626 if (!ok)
2627 SetErrBreak (("SetupDiSetSelectedDriver failed (0x%08X)",
2628 GetLastError()));
2629
2630 /* register the phantom device to prepare for install */
2631 ok = SetupDiCallClassInstaller (DIF_REGISTERDEVICE, hDeviceInfo,
2632 &DeviceInfoData);
2633 if (!ok)
2634 SetErrBreak (("SetupDiCallClassInstaller failed (0x%08X)",
2635 GetLastError()));
2636
2637 /* registered, but remove if errors occur in the following code */
2638 registered = TRUE;
2639
2640 /* ask the installer if we can install the device */
2641 ok = SetupDiCallClassInstaller (DIF_ALLOW_INSTALL, hDeviceInfo,
2642 &DeviceInfoData);
2643 if (!ok)
2644 {
2645 if (GetLastError() != ERROR_DI_DO_DEFAULT)
2646 SetErrBreak (("SetupDiCallClassInstaller (DIF_ALLOW_INSTALL) failed (0x%08X)",
2647 GetLastError()));
2648 /* that's fine */
2649 }
2650
2651 /* install the files first */
2652 ok = SetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES, hDeviceInfo,
2653 &DeviceInfoData);
2654 if (!ok)
2655 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES) failed (0x%08X)",
2656 GetLastError()));
2657
2658 /* get the device install parameters and disable filecopy */
2659 DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
2660 ok = SetupDiGetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
2661 &DeviceInstallParams);
2662 if (ok)
2663 {
2664 DeviceInstallParams.Flags |= DI_NOFILECOPY;
2665 ok = SetupDiSetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
2666 &DeviceInstallParams);
2667 if (!ok)
2668 SetErrBreak (("SetupDiSetDeviceInstallParams failed (0x%08X)",
2669 GetLastError()));
2670 }
2671
2672 /*
2673 * Register any device-specific co-installers for this device,
2674 */
2675
2676 ok = SetupDiCallClassInstaller (DIF_REGISTER_COINSTALLERS,
2677 hDeviceInfo,
2678 &DeviceInfoData);
2679 if (!ok)
2680 SetErrBreak (("SetupDiCallClassInstaller (DIF_REGISTER_COINSTALLERS) failed (0x%08X)",
2681 GetLastError()));
2682
2683 /*
2684 * install any installer-specified interfaces.
2685 * and then do the real install
2686 */
2687 ok = SetupDiCallClassInstaller (DIF_INSTALLINTERFACES,
2688 hDeviceInfo,
2689 &DeviceInfoData);
2690 if (!ok)
2691 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLINTERFACES) failed (0x%08X)",
2692 GetLastError()));
2693
2694 ok = SetupDiCallClassInstaller (DIF_INSTALLDEVICE,
2695 hDeviceInfo,
2696 &DeviceInfoData);
2697 if (!ok)
2698 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLDEVICE) failed (0x%08X)",
2699 GetLastError()));
2700
2701 /* Figure out NetCfgInstanceId */
2702 hkey = SetupDiOpenDevRegKey (hDeviceInfo,
2703 &DeviceInfoData,
2704 DICS_FLAG_GLOBAL,
2705 0,
2706 DIREG_DRV,
2707 KEY_READ);
2708 if (hkey == INVALID_HANDLE_VALUE)
2709 SetErrBreak (("SetupDiOpenDevRegKey failed (0x%08X)",
2710 GetLastError()));
2711
2712 cbSize = sizeof (pCfgGuidString);
2713 DWORD ret;
2714 ret = RegQueryValueEx (hkey, _T ("NetCfgInstanceId"), NULL,
2715 &dwValueType, (LPBYTE) pCfgGuidString, &cbSize);
2716 RegCloseKey (hkey);
2717
2718 ret = RenameConnection (pCfgGuidString, Bstr (aName));
2719 if (FAILED (ret))
2720 SetErrBreak (("Failed to set interface name (ret=0x%08X, "
2721 "pCfgGuidString='%ls', cbSize=%d)",
2722 ret, pCfgGuidString, cbSize));
2723 }
2724 while (0);
2725
2726 /*
2727 * cleanup
2728 */
2729
2730 if (hDeviceInfo != INVALID_HANDLE_VALUE)
2731 {
2732 /* an error has occured, but the device is registered, we must remove it */
2733 if (ret != 0 && registered)
2734 SetupDiCallClassInstaller (DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
2735
2736 found = SetupDiDeleteDeviceInfo (hDeviceInfo, &DeviceInfoData);
2737
2738 /* destroy the driver info list */
2739 if (destroyList)
2740 SetupDiDestroyDriverInfoList (hDeviceInfo, &DeviceInfoData,
2741 SPDIT_CLASSDRIVER);
2742 /* clean up the device info set */
2743 SetupDiDestroyDeviceInfoList (hDeviceInfo);
2744 }
2745
2746 /* return the network connection GUID on success */
2747 if (RT_SUCCESS (vrc))
2748 {
2749 /* remove the curly bracket at the end */
2750 pCfgGuidString [_tcslen (pCfgGuidString) - 1] = '\0';
2751 LogFlowFunc (("Network connection GUID string = {%ls}\n", pCfgGuidString + 1));
2752
2753 aGUID = Guid (Utf8Str (pCfgGuidString + 1));
2754 LogFlowFunc (("Network connection GUID = {%RTuuid}\n", aGUID.raw()));
2755 Assert (!aGUID.isEmpty());
2756 }
2757
2758 LogFlowFunc (("vrc=%Rrc\n", vrc));
2759 LogFlowFuncLeave();
2760 return vrc;
2761}
2762
2763/* static */
2764int Host::removeNetworkInterface (SVCHlpClient *aClient,
2765 const Guid &aGUID,
2766 Utf8Str &aErrMsg)
2767{
2768 LogFlowFuncEnter();
2769 LogFlowFunc (("Network connection GUID = {%RTuuid}\n", aGUID.raw()));
2770
2771 AssertReturn (aClient, VERR_INVALID_POINTER);
2772 AssertReturn (!aGUID.isEmpty(), VERR_INVALID_PARAMETER);
2773
2774 int vrc = VINF_SUCCESS;
2775
2776 do
2777 {
2778 TCHAR lszPnPInstanceId [512] = {0};
2779
2780 /* We have to find the device instance ID through a registry search */
2781
2782 HKEY hkeyNetwork = 0;
2783 HKEY hkeyConnection = 0;
2784
2785 do
2786 {
2787 char strRegLocation [256];
2788 sprintf (strRegLocation,
2789 "SYSTEM\\CurrentControlSet\\Control\\Network\\"
2790 "{4D36E972-E325-11CE-BFC1-08002BE10318}\\{%s}",
2791 aGUID.toString().raw());
2792 LONG status;
2793 status = RegOpenKeyExA (HKEY_LOCAL_MACHINE, strRegLocation, 0,
2794 KEY_READ, &hkeyNetwork);
2795 if ((status != ERROR_SUCCESS) || !hkeyNetwork)
2796 SetErrBreak ((
2797 tr ("Host interface network is not found in registry (%s) [1]"),
2798 strRegLocation));
2799
2800 status = RegOpenKeyExA (hkeyNetwork, "Connection", 0,
2801 KEY_READ, &hkeyConnection);
2802 if ((status != ERROR_SUCCESS) || !hkeyConnection)
2803 SetErrBreak ((
2804 tr ("Host interface network is not found in registry (%s) [2]"),
2805 strRegLocation));
2806
2807 DWORD len = sizeof (lszPnPInstanceId);
2808 DWORD dwKeyType;
2809 status = RegQueryValueExW (hkeyConnection, L"PnPInstanceID", NULL,
2810 &dwKeyType, (LPBYTE) lszPnPInstanceId, &len);
2811 if ((status != ERROR_SUCCESS) || (dwKeyType != REG_SZ))
2812 SetErrBreak ((
2813 tr ("Host interface network is not found in registry (%s) [3]"),
2814 strRegLocation));
2815 }
2816 while (0);
2817
2818 if (hkeyConnection)
2819 RegCloseKey (hkeyConnection);
2820 if (hkeyNetwork)
2821 RegCloseKey (hkeyNetwork);
2822
2823 if (RT_FAILURE (vrc))
2824 break;
2825
2826 /*
2827 * Now we are going to enumerate all network devices and
2828 * wait until we encounter the right device instance ID
2829 */
2830
2831 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
2832
2833 do
2834 {
2835 BOOL ok;
2836 DWORD ret = 0;
2837 GUID netGuid;
2838 SP_DEVINFO_DATA DeviceInfoData;
2839 DWORD index = 0;
2840 BOOL found = FALSE;
2841 DWORD size = 0;
2842
2843 /* initialize the structure size */
2844 DeviceInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
2845
2846 /* copy the net class GUID */
2847 memcpy (&netGuid, &GUID_DEVCLASS_NET, sizeof (GUID_DEVCLASS_NET));
2848
2849 /* return a device info set contains all installed devices of the Net class */
2850 hDeviceInfo = SetupDiGetClassDevs (&netGuid, NULL, NULL, DIGCF_PRESENT);
2851
2852 if (hDeviceInfo == INVALID_HANDLE_VALUE)
2853 SetErrBreak (("SetupDiGetClassDevs failed (0x%08X)", GetLastError()));
2854
2855 /* enumerate the driver info list */
2856 while (TRUE)
2857 {
2858 TCHAR *deviceHwid;
2859
2860 ok = SetupDiEnumDeviceInfo (hDeviceInfo, index, &DeviceInfoData);
2861
2862 if (!ok)
2863 {
2864 if (GetLastError() == ERROR_NO_MORE_ITEMS)
2865 break;
2866 else
2867 {
2868 index++;
2869 continue;
2870 }
2871 }
2872
2873 /* try to get the hardware ID registry property */
2874 ok = SetupDiGetDeviceRegistryProperty (hDeviceInfo,
2875 &DeviceInfoData,
2876 SPDRP_HARDWAREID,
2877 NULL,
2878 NULL,
2879 0,
2880 &size);
2881 if (!ok)
2882 {
2883 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
2884 {
2885 index++;
2886 continue;
2887 }
2888
2889 deviceHwid = (TCHAR *) malloc (size);
2890 ok = SetupDiGetDeviceRegistryProperty (hDeviceInfo,
2891 &DeviceInfoData,
2892 SPDRP_HARDWAREID,
2893 NULL,
2894 (PBYTE)deviceHwid,
2895 size,
2896 NULL);
2897 if (!ok)
2898 {
2899 free (deviceHwid);
2900 deviceHwid = NULL;
2901 index++;
2902 continue;
2903 }
2904 }
2905 else
2906 {
2907 /* something is wrong. This shouldn't have worked with a NULL buffer */
2908 index++;
2909 continue;
2910 }
2911
2912 for (TCHAR *t = deviceHwid;
2913 t && *t && t < &deviceHwid[size / sizeof(TCHAR)];
2914 t += _tcslen (t) + 1)
2915 {
2916 if (!_tcsicmp (DRIVERHWID, t))
2917 {
2918 /* get the device instance ID */
2919 TCHAR devID [MAX_DEVICE_ID_LEN];
2920 if (CM_Get_Device_ID(DeviceInfoData.DevInst,
2921 devID, MAX_DEVICE_ID_LEN, 0) == CR_SUCCESS)
2922 {
2923 /* compare to what we determined before */
2924 if (wcscmp(devID, lszPnPInstanceId) == 0)
2925 {
2926 found = TRUE;
2927 break;
2928 }
2929 }
2930 }
2931 }
2932
2933 if (deviceHwid)
2934 {
2935 free (deviceHwid);
2936 deviceHwid = NULL;
2937 }
2938
2939 if (found)
2940 break;
2941
2942 index++;
2943 }
2944
2945 if (found == FALSE)
2946 SetErrBreak ((tr ("Host Interface Network driver not found (0x%08X)"),
2947 GetLastError()));
2948
2949 ok = SetupDiSetSelectedDevice (hDeviceInfo, &DeviceInfoData);
2950 if (!ok)
2951 SetErrBreak (("SetupDiSetSelectedDevice failed (0x%08X)",
2952 GetLastError()));
2953
2954 ok = SetupDiCallClassInstaller (DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
2955 if (!ok)
2956 SetErrBreak (("SetupDiCallClassInstaller (DIF_REMOVE) failed (0x%08X)",
2957 GetLastError()));
2958 }
2959 while (0);
2960
2961 /* clean up the device info set */
2962 if (hDeviceInfo != INVALID_HANDLE_VALUE)
2963 SetupDiDestroyDeviceInfoList (hDeviceInfo);
2964
2965 if (RT_FAILURE (vrc))
2966 break;
2967 }
2968 while (0);
2969
2970 LogFlowFunc (("vrc=%Rrc\n", vrc));
2971 LogFlowFuncLeave();
2972 return vrc;
2973}
2974
2975#undef SetErrBreak
2976
2977/* static */
2978HRESULT Host::networkInterfaceHelperClient (SVCHlpClient *aClient,
2979 Progress *aProgress,
2980 void *aUser, int *aVrc)
2981{
2982 LogFlowFuncEnter();
2983 LogFlowFunc (("aClient={%p}, aProgress={%p}, aUser={%p}\n",
2984 aClient, aProgress, aUser));
2985
2986 AssertReturn ((aClient == NULL && aProgress == NULL && aVrc == NULL) ||
2987 (aClient != NULL && aProgress != NULL && aVrc != NULL),
2988 E_POINTER);
2989 AssertReturn (aUser, E_POINTER);
2990
2991 std::auto_ptr <NetworkInterfaceHelperClientData>
2992 d (static_cast <NetworkInterfaceHelperClientData *> (aUser));
2993
2994 if (aClient == NULL)
2995 {
2996 /* "cleanup only" mode, just return (it will free aUser) */
2997 return S_OK;
2998 }
2999
3000 HRESULT rc = S_OK;
3001 int vrc = VINF_SUCCESS;
3002
3003 switch (d->msgCode)
3004 {
3005 case SVCHlpMsg::CreateHostOnlyNetworkInterface:
3006 {
3007 LogFlowFunc (("CreateHostOnlyNetworkInterface:\n"));
3008 LogFlowFunc (("Network connection name = '%ls'\n", d->name.raw()));
3009
3010 /* write message and parameters */
3011 vrc = aClient->write (d->msgCode);
3012 if (RT_FAILURE (vrc)) break;
3013 vrc = aClient->write (Utf8Str (d->name));
3014 if (RT_FAILURE (vrc)) break;
3015
3016 /* wait for a reply */
3017 bool endLoop = false;
3018 while (!endLoop)
3019 {
3020 SVCHlpMsg::Code reply = SVCHlpMsg::Null;
3021
3022 vrc = aClient->read (reply);
3023 if (RT_FAILURE (vrc)) break;
3024
3025 switch (reply)
3026 {
3027 case SVCHlpMsg::CreateHostOnlyNetworkInterface_OK:
3028 {
3029 /* read the GUID */
3030 Guid guid;
3031 vrc = aClient->read (guid);
3032 if (RT_FAILURE (vrc)) break;
3033
3034 LogFlowFunc (("Network connection GUID = {%RTuuid}\n", guid.raw()));
3035
3036 /* initialize the object returned to the caller by
3037 * CreateHostOnlyNetworkInterface() */
3038 rc = d->iface->init (d->name, guid, HostNetworkInterfaceType_HostOnly);
3039 endLoop = true;
3040 break;
3041 }
3042 case SVCHlpMsg::Error:
3043 {
3044 /* read the error message */
3045 Utf8Str errMsg;
3046 vrc = aClient->read (errMsg);
3047 if (RT_FAILURE (vrc)) break;
3048
3049 rc = setError (E_FAIL, errMsg);
3050 endLoop = true;
3051 break;
3052 }
3053 default:
3054 {
3055 endLoop = true;
3056 ComAssertMsgFailedBreak ((
3057 "Invalid message code %d (%08lX)\n",
3058 reply, reply),
3059 rc = E_FAIL);
3060 }
3061 }
3062 }
3063
3064 break;
3065 }
3066 case SVCHlpMsg::RemoveHostOnlyNetworkInterface:
3067 {
3068 LogFlowFunc (("RemoveHostOnlyNetworkInterface:\n"));
3069 LogFlowFunc (("Network connection GUID = {%RTuuid}\n", d->guid.raw()));
3070
3071 /* write message and parameters */
3072 vrc = aClient->write (d->msgCode);
3073 if (RT_FAILURE (vrc)) break;
3074 vrc = aClient->write (d->guid);
3075 if (RT_FAILURE (vrc)) break;
3076
3077 /* wait for a reply */
3078 bool endLoop = false;
3079 while (!endLoop)
3080 {
3081 SVCHlpMsg::Code reply = SVCHlpMsg::Null;
3082
3083 vrc = aClient->read (reply);
3084 if (RT_FAILURE (vrc)) break;
3085
3086 switch (reply)
3087 {
3088 case SVCHlpMsg::OK:
3089 {
3090 /* no parameters */
3091 rc = S_OK;
3092 endLoop = true;
3093 break;
3094 }
3095 case SVCHlpMsg::Error:
3096 {
3097 /* read the error message */
3098 Utf8Str errMsg;
3099 vrc = aClient->read (errMsg);
3100 if (RT_FAILURE (vrc)) break;
3101
3102 rc = setError (E_FAIL, errMsg);
3103 endLoop = true;
3104 break;
3105 }
3106 default:
3107 {
3108 endLoop = true;
3109 ComAssertMsgFailedBreak ((
3110 "Invalid message code %d (%08lX)\n",
3111 reply, reply),
3112 rc = E_FAIL);
3113 }
3114 }
3115 }
3116
3117 break;
3118 }
3119 default:
3120 ComAssertMsgFailedBreak ((
3121 "Invalid message code %d (%08lX)\n",
3122 d->msgCode, d->msgCode),
3123 rc = E_FAIL);
3124 }
3125
3126 if (aVrc)
3127 *aVrc = vrc;
3128
3129 LogFlowFunc (("rc=0x%08X, vrc=%Rrc\n", rc, vrc));
3130 LogFlowFuncLeave();
3131 return rc;
3132}
3133
3134/* static */
3135int Host::networkInterfaceHelperServer (SVCHlpClient *aClient,
3136 SVCHlpMsg::Code aMsgCode)
3137{
3138 LogFlowFuncEnter();
3139 LogFlowFunc (("aClient={%p}, aMsgCode=%d\n", aClient, aMsgCode));
3140
3141 AssertReturn (aClient, VERR_INVALID_POINTER);
3142
3143 int vrc = VINF_SUCCESS;
3144
3145 switch (aMsgCode)
3146 {
3147 case SVCHlpMsg::CreateHostOnlyNetworkInterface:
3148 {
3149 LogFlowFunc (("CreateHostOnlyNetworkInterface:\n"));
3150
3151 Utf8Str name;
3152 vrc = aClient->read (name);
3153 if (RT_FAILURE (vrc)) break;
3154
3155 Guid guid;
3156 Utf8Str errMsg;
3157 vrc = createNetworkInterface (aClient, name, guid, errMsg);
3158
3159 if (RT_SUCCESS (vrc))
3160 {
3161 /* write success followed by GUID */
3162 vrc = aClient->write (SVCHlpMsg::CreateHostOnlyNetworkInterface_OK);
3163 if (RT_FAILURE (vrc)) break;
3164 vrc = aClient->write (guid);
3165 if (RT_FAILURE (vrc)) break;
3166 }
3167 else
3168 {
3169 /* write failure followed by error message */
3170 if (errMsg.isEmpty())
3171 errMsg = Utf8StrFmt ("Unspecified error (%Rrc)", vrc);
3172 vrc = aClient->write (SVCHlpMsg::Error);
3173 if (RT_FAILURE (vrc)) break;
3174 vrc = aClient->write (errMsg);
3175 if (RT_FAILURE (vrc)) break;
3176 }
3177
3178 break;
3179 }
3180 case SVCHlpMsg::RemoveHostOnlyNetworkInterface:
3181 {
3182 LogFlowFunc (("RemoveHostOnlyNetworkInterface:\n"));
3183
3184 Guid guid;
3185 vrc = aClient->read (guid);
3186 if (RT_FAILURE (vrc)) break;
3187
3188 Utf8Str errMsg;
3189 vrc = removeNetworkInterface (aClient, guid, errMsg);
3190
3191 if (RT_SUCCESS (vrc))
3192 {
3193 /* write parameter-less success */
3194 vrc = aClient->write (SVCHlpMsg::OK);
3195 if (RT_FAILURE (vrc)) break;
3196 }
3197 else
3198 {
3199 /* write failure followed by error message */
3200 if (errMsg.isEmpty())
3201 errMsg = Utf8StrFmt ("Unspecified error (%Rrc)", vrc);
3202 vrc = aClient->write (SVCHlpMsg::Error);
3203 if (RT_FAILURE (vrc)) break;
3204 vrc = aClient->write (errMsg);
3205 if (RT_FAILURE (vrc)) break;
3206 }
3207
3208 break;
3209 }
3210 default:
3211 AssertMsgFailedBreakStmt (
3212 ("Invalid message code %d (%08lX)\n", aMsgCode, aMsgCode),
3213 VERR_GENERAL_FAILURE);
3214 }
3215
3216 LogFlowFunc (("vrc=%Rrc\n", vrc));
3217 LogFlowFuncLeave();
3218 return vrc;
3219}
3220
3221#endif /* RT_OS_WINDOWS */
3222
3223#ifdef VBOX_WITH_RESOURCE_USAGE_API
3224void Host::registerMetrics (PerformanceCollector *aCollector)
3225{
3226 pm::CollectorHAL *hal = aCollector->getHAL();
3227 /* Create sub metrics */
3228 pm::SubMetric *cpuLoadUser = new pm::SubMetric ("CPU/Load/User",
3229 "Percentage of processor time spent in user mode.");
3230 pm::SubMetric *cpuLoadKernel = new pm::SubMetric ("CPU/Load/Kernel",
3231 "Percentage of processor time spent in kernel mode.");
3232 pm::SubMetric *cpuLoadIdle = new pm::SubMetric ("CPU/Load/Idle",
3233 "Percentage of processor time spent idling.");
3234 pm::SubMetric *cpuMhzSM = new pm::SubMetric ("CPU/MHz",
3235 "Average of current frequency of all processors.");
3236 pm::SubMetric *ramUsageTotal = new pm::SubMetric ("RAM/Usage/Total",
3237 "Total physical memory installed.");
3238 pm::SubMetric *ramUsageUsed = new pm::SubMetric ("RAM/Usage/Used",
3239 "Physical memory currently occupied.");
3240 pm::SubMetric *ramUsageFree = new pm::SubMetric ("RAM/Usage/Free",
3241 "Physical memory currently available to applications.");
3242 /* Create and register base metrics */
3243 IUnknown *objptr;
3244 ComObjPtr <Host> tmp = this;
3245 tmp.queryInterfaceTo (&objptr);
3246 pm::BaseMetric *cpuLoad = new pm::HostCpuLoadRaw (hal, objptr, cpuLoadUser, cpuLoadKernel,
3247 cpuLoadIdle);
3248 aCollector->registerBaseMetric (cpuLoad);
3249 pm::BaseMetric *cpuMhz = new pm::HostCpuMhz (hal, objptr, cpuMhzSM);
3250 aCollector->registerBaseMetric (cpuMhz);
3251 pm::BaseMetric *ramUsage = new pm::HostRamUsage (hal, objptr, ramUsageTotal, ramUsageUsed,
3252 ramUsageFree);
3253 aCollector->registerBaseMetric (ramUsage);
3254
3255 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadUser, 0));
3256 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadUser,
3257 new pm::AggregateAvg()));
3258 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadUser,
3259 new pm::AggregateMin()));
3260 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadUser,
3261 new pm::AggregateMax()));
3262
3263 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadKernel, 0));
3264 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadKernel,
3265 new pm::AggregateAvg()));
3266 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadKernel,
3267 new pm::AggregateMin()));
3268 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadKernel,
3269 new pm::AggregateMax()));
3270
3271 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadIdle, 0));
3272 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadIdle,
3273 new pm::AggregateAvg()));
3274 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadIdle,
3275 new pm::AggregateMin()));
3276 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadIdle,
3277 new pm::AggregateMax()));
3278
3279 aCollector->registerMetric (new pm::Metric(cpuMhz, cpuMhzSM, 0));
3280 aCollector->registerMetric (new pm::Metric(cpuMhz, cpuMhzSM,
3281 new pm::AggregateAvg()));
3282 aCollector->registerMetric (new pm::Metric(cpuMhz, cpuMhzSM,
3283 new pm::AggregateMin()));
3284 aCollector->registerMetric (new pm::Metric(cpuMhz, cpuMhzSM,
3285 new pm::AggregateMax()));
3286
3287 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageTotal, 0));
3288 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageTotal,
3289 new pm::AggregateAvg()));
3290 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageTotal,
3291 new pm::AggregateMin()));
3292 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageTotal,
3293 new pm::AggregateMax()));
3294
3295 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageUsed, 0));
3296 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageUsed,
3297 new pm::AggregateAvg()));
3298 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageUsed,
3299 new pm::AggregateMin()));
3300 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageUsed,
3301 new pm::AggregateMax()));
3302
3303 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageFree, 0));
3304 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageFree,
3305 new pm::AggregateAvg()));
3306 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageFree,
3307 new pm::AggregateMin()));
3308 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageFree,
3309 new pm::AggregateMax()));
3310};
3311
3312void Host::unregisterMetrics (PerformanceCollector *aCollector)
3313{
3314 aCollector->unregisterMetricsFor (this);
3315 aCollector->unregisterBaseMetricsFor (this);
3316};
3317#endif /* VBOX_WITH_RESOURCE_USAGE_API */
3318
3319STDMETHODIMP Host::FindHostDVDDrive(IN_BSTR aName, IHostDVDDrive **aDrive)
3320{
3321 CheckComArgNotNull(aName);
3322 CheckComArgOutPointerValid(aDrive);
3323
3324 *aDrive = NULL;
3325
3326 SafeIfaceArray <IHostDVDDrive> drivevec;
3327 HRESULT rc = COMGETTER(DVDDrives) (ComSafeArrayAsOutParam(drivevec));
3328 CheckComRCReturnRC (rc);
3329
3330 for (size_t i = 0; i < drivevec.size(); ++i)
3331 {
3332 Bstr name;
3333 rc = drivevec[i]->COMGETTER(Name) (name.asOutParam());
3334 CheckComRCReturnRC (rc);
3335 if (name == aName)
3336 {
3337 ComObjPtr<HostDVDDrive> found;
3338 found.createObject();
3339 Bstr udi, description;
3340 rc = drivevec[i]->COMGETTER(Udi) (udi.asOutParam());
3341 CheckComRCReturnRC (rc);
3342 rc = drivevec[i]->COMGETTER(Description) (description.asOutParam());
3343 CheckComRCReturnRC (rc);
3344 found->init(name, udi, description);
3345 return found.queryInterfaceTo(aDrive);
3346 }
3347 }
3348
3349 return setError (VBOX_E_OBJECT_NOT_FOUND, HostDVDDrive::tr (
3350 "The host DVD drive named '%ls' could not be found"), aName);
3351}
3352
3353STDMETHODIMP Host::FindHostFloppyDrive(IN_BSTR aName, IHostFloppyDrive **aDrive)
3354{
3355 CheckComArgNotNull(aName);
3356 CheckComArgOutPointerValid(aDrive);
3357
3358 *aDrive = NULL;
3359
3360 SafeIfaceArray <IHostFloppyDrive> drivevec;
3361 HRESULT rc = COMGETTER(FloppyDrives) (ComSafeArrayAsOutParam(drivevec));
3362 CheckComRCReturnRC (rc);
3363
3364 for (size_t i = 0; i < drivevec.size(); ++i)
3365 {
3366 Bstr name;
3367 rc = drivevec[i]->COMGETTER(Name) (name.asOutParam());
3368 CheckComRCReturnRC (rc);
3369 if (name == aName)
3370 {
3371 ComObjPtr<HostFloppyDrive> found;
3372 found.createObject();
3373 Bstr udi, description;
3374 rc = drivevec[i]->COMGETTER(Udi) (udi.asOutParam());
3375 CheckComRCReturnRC (rc);
3376 rc = drivevec[i]->COMGETTER(Description) (description.asOutParam());
3377 CheckComRCReturnRC (rc);
3378 found->init(name, udi, description);
3379 return found.queryInterfaceTo(aDrive);
3380 }
3381 }
3382
3383 return setError (VBOX_E_OBJECT_NOT_FOUND, HostFloppyDrive::tr (
3384 "The host floppy drive named '%ls' could not be found"), aName);
3385}
3386
3387STDMETHODIMP Host::FindHostNetworkInterfaceByName(IN_BSTR name, IHostNetworkInterface **networkInterface)
3388{
3389#ifndef VBOX_WITH_HOSTNETIF_API
3390 return E_NOTIMPL;
3391#else
3392 if (!name)
3393 return E_INVALIDARG;
3394 if (!networkInterface)
3395 return E_POINTER;
3396
3397 *networkInterface = NULL;
3398 ComObjPtr <HostNetworkInterface> found;
3399 std::list <ComObjPtr <HostNetworkInterface> > list;
3400 int rc = NetIfList(list);
3401 if (RT_FAILURE(rc))
3402 {
3403 Log(("Failed to get host network interface list with rc=%Vrc\n", rc));
3404 return E_FAIL;
3405 }
3406 std::list <ComObjPtr <HostNetworkInterface> >::iterator it;
3407 for (it = list.begin(); it != list.end(); ++it)
3408 {
3409 Bstr n;
3410 (*it)->COMGETTER(Name) (n.asOutParam());
3411 if (n == name)
3412 found = *it;
3413 }
3414
3415 if (!found)
3416 return setError (E_INVALIDARG, HostNetworkInterface::tr (
3417 "The host network interface with the given name could not be found"));
3418
3419 return found.queryInterfaceTo (networkInterface);
3420#endif
3421}
3422
3423STDMETHODIMP Host::FindHostNetworkInterfaceById(IN_GUID id, IHostNetworkInterface **networkInterface)
3424{
3425#ifndef VBOX_WITH_HOSTNETIF_API
3426 return E_NOTIMPL;
3427#else
3428 if (Guid(id).isEmpty())
3429 return E_INVALIDARG;
3430 if (!networkInterface)
3431 return E_POINTER;
3432
3433 *networkInterface = NULL;
3434 ComObjPtr <HostNetworkInterface> found;
3435 std::list <ComObjPtr <HostNetworkInterface> > list;
3436 int rc = NetIfList(list);
3437 if (RT_FAILURE(rc))
3438 {
3439 Log(("Failed to get host network interface list with rc=%Vrc\n", rc));
3440 return E_FAIL;
3441 }
3442 std::list <ComObjPtr <HostNetworkInterface> >::iterator it;
3443 for (it = list.begin(); it != list.end(); ++it)
3444 {
3445 Guid g;
3446 (*it)->COMGETTER(Id) (g.asOutParam());
3447 if (g == Guid(id))
3448 found = *it;
3449 }
3450
3451 if (!found)
3452 return setError (E_INVALIDARG, HostNetworkInterface::tr (
3453 "The host network interface with the given GUID could not be found"));
3454
3455 return found.queryInterfaceTo (networkInterface);
3456#endif
3457}
3458
3459STDMETHODIMP Host::FindHostNetworkInterfacesOfType(HostNetworkInterfaceType_T type, ComSafeArrayOut (IHostNetworkInterface *, aNetworkInterfaces))
3460{
3461 com::SafeIfaceArray <IHostNetworkInterface> hostNetworkInterfaces;
3462 HRESULT hr = COMGETTER(NetworkInterfaces) (ComSafeArrayAsOutParam (hostNetworkInterfaces));
3463 if(FAILED(hr))
3464 {
3465 return hr;
3466 }
3467
3468 std::list <ComObjPtr <IHostNetworkInterface> > list;
3469
3470 for (size_t i = 0; i < hostNetworkInterfaces.size(); ++i)
3471 {
3472 IHostNetworkInterface * networkInterface = hostNetworkInterfaces[i];
3473 HostNetworkInterfaceType_T t;
3474 hr = networkInterface->COMGETTER(InterfaceType)(&t);
3475 if(FAILED(hr))
3476 {
3477 return hr;
3478 }
3479
3480 if(t == type)
3481 {
3482 list.push_back (networkInterface);
3483 }
3484 }
3485
3486 SafeIfaceArray <IHostNetworkInterface> filteredNetworkInterfaces (list);
3487 filteredNetworkInterfaces.detachTo (ComSafeArrayOutArg (aNetworkInterfaces));
3488
3489 return S_OK;
3490}
3491
3492
3493/* 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