VirtualBox

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

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

Stubs for all platforms. Implementation of host CPU load and RAM usage counters for Windows. Locking. Fixes.

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