VirtualBox

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

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

Main & VBoxManage: Made HostNetworkInterface, IHost::networkInterfaces and list hostifs available everywhere. Only Windows and Darwin implements the enumeration.

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