VirtualBox

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

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

Main: Solaris NIC listing, make it avoid duplicates.

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