VirtualBox

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

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

Remove unwanted header.

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