VirtualBox

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

Last change on this file since 2929 was 2929, checked in by vboxsync, 17 years ago

Main: Removed devNode from the host DVD drive description (it's up to UI to decide how to visually represent things); switched HostDVDDrive and HostFloppyDrive objects to the new locking scheme.

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