VirtualBox

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

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

PerfAPI: Improved Win collector. More realistic performance test. No factories.

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