VirtualBox

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

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

NetFlt friver installation moved to the installer

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