VirtualBox

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

Last change on this file since 12861 was 12785, checked in by vboxsync, 17 years ago

Main: Solaris/vboxnetflt: Hostif NIC Uuid fix.

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

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