VirtualBox

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

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

Actaully, RTMpGetMaxFrequency is more appropriate. An associated API would be RTMpGetCurFrequency.

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