VirtualBox

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

Last change on this file since 2917 was 2917, checked in by vboxsync, 18 years ago

Updated the host DVD code on Linux to use hal for device detection

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 88.5 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 char description[256];
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))
1437 {
1438 if (vendor != 0 && vendor[0] != 0)
1439 {
1440 RTStrPrintf(description, sizeof(description),
1441 "%s %s (%s)", vendor, product, devNode);
1442 }
1443 else
1444 {
1445 RTStrPrintf(description, sizeof(description),
1446 "%s (%s)", product, devNode);
1447 }
1448 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
1449 hostDVDDriveObj.createObject();
1450 hostDVDDriveObj->init (Bstr (devNode), Bstr (description));
1451 list.push_back (hostDVDDriveObj);
1452 }
1453 else
1454 {
1455 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
1456 hostDVDDriveObj.createObject();
1457 hostDVDDriveObj->init (Bstr (devNode));
1458 list.push_back (hostDVDDriveObj);
1459 }
1460 }
1461 else
1462 {
1463 LogRel(("Host::COMGETTER(DVDDrives): failed to validate the block device %s as a DVD drive\n"));
1464 }
1465 libhal_free_string(devNode);
1466 }
1467 else
1468 {
1469 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
1470 halDevices[i], dbusError.name, dbusError.message));
1471 dbus_error_free(&dbusError);
1472 }
1473 }
1474 libhal_free_string_array(halDevices);
1475 }
1476 else
1477 {
1478 LogRel(("Host::COMGETTER(DVDDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1479 dbus_error_free(&dbusError);
1480 }
1481 if (!libhal_ctx_shutdown(halContext, &dbusError)) /* what now? */
1482 {
1483 LogRel(("Host::COMGETTER(DVDDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1484 dbus_error_free(&dbusError);
1485 }
1486 }
1487 else
1488 {
1489 LogRel(("Host::COMGETTER(DVDDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1490 dbus_error_free(&dbusError);
1491 }
1492 libhal_ctx_free(halContext);
1493 }
1494 else
1495 {
1496 LogRel(("Host::COMGETTER(DVDDrives): failed to set libhal connection to dbus.\n"));
1497 }
1498 }
1499 else
1500 {
1501 LogRel(("Host::COMGETTER(DVDDrives): failed to get a libhal context - out of memory?\n"));
1502 }
1503 dbus_connection_unref(dbusConnection);
1504 }
1505 else
1506 {
1507 LogRel(("Host::COMGETTER(DVDDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1508 dbus_error_free(&dbusError);
1509 }
1510 return halSuccess;
1511}
1512# endif /* VBOX_USE_HAL defined */
1513
1514/**
1515 * Helper function to parse the given mount file and add found entries
1516 */
1517void Host::parseMountTable(char *mountTable, std::list <ComObjPtr <HostDVDDrive> > &list)
1518{
1519 FILE *mtab = setmntent(mountTable, "r");
1520 if (mtab)
1521 {
1522 struct mntent *mntent;
1523 char *mnt_type;
1524 char *mnt_dev;
1525 char *tmp;
1526 while ((mntent = getmntent(mtab)))
1527 {
1528 mnt_type = (char*)malloc(strlen(mntent->mnt_type) + 1);
1529 mnt_dev = (char*)malloc(strlen(mntent->mnt_fsname) + 1);
1530 strcpy(mnt_type, mntent->mnt_type);
1531 strcpy(mnt_dev, mntent->mnt_fsname);
1532 // supermount fs case
1533 if (strcmp(mnt_type, "supermount") == 0)
1534 {
1535 tmp = strstr(mntent->mnt_opts, "fs=");
1536 if (tmp)
1537 {
1538 free(mnt_type);
1539 mnt_type = strdup(tmp + strlen("fs="));
1540 if (mnt_type)
1541 {
1542 tmp = strchr(mnt_type, ',');
1543 if (tmp)
1544 {
1545 *tmp = '\0';
1546 }
1547 }
1548 }
1549 tmp = strstr(mntent->mnt_opts, "dev=");
1550 if (tmp)
1551 {
1552 free(mnt_dev);
1553 mnt_dev = strdup(tmp + strlen("dev="));
1554 if (mnt_dev)
1555 {
1556 tmp = strchr(mnt_dev, ',');
1557 if (tmp)
1558 {
1559 *tmp = '\0';
1560 }
1561 }
1562 }
1563 }
1564 if (strcmp(mnt_type, "iso9660") == 0)
1565 {
1566 /** @todo check whether we've already got the drive in our list! */
1567 if (validateDevice(mnt_dev, true))
1568 {
1569 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
1570 hostDVDDriveObj.createObject();
1571 hostDVDDriveObj->init (Bstr (mnt_dev));
1572 list.push_back (hostDVDDriveObj);
1573 }
1574 }
1575 free(mnt_dev);
1576 free(mnt_type);
1577 }
1578 endmntent(mtab);
1579 }
1580}
1581
1582/**
1583 * Helper function to check whether the given device node is a valid drive
1584 */
1585bool Host::validateDevice(const char *deviceNode, bool isCDROM)
1586{
1587 struct stat statInfo;
1588 bool retValue = false;
1589
1590 // sanity check
1591 if (!deviceNode)
1592 {
1593 return false;
1594 }
1595
1596 // first a simple stat() call
1597 if (stat(deviceNode, &statInfo) < 0)
1598 {
1599 return false;
1600 } else
1601 {
1602 if (isCDROM)
1603 {
1604 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
1605 {
1606 int fileHandle;
1607 // now try to open the device
1608 fileHandle = open(deviceNode, O_RDONLY | O_NONBLOCK, 0);
1609 if (fileHandle >= 0)
1610 {
1611 cdrom_subchnl cdChannelInfo;
1612 cdChannelInfo.cdsc_format = CDROM_MSF;
1613 // this call will finally reveal the whole truth
1614 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
1615 (errno == EIO) || (errno == ENOENT) ||
1616 (errno == EINVAL) || (errno == ENOMEDIUM))
1617 {
1618 retValue = true;
1619 }
1620 close(fileHandle);
1621 }
1622 }
1623 } else
1624 {
1625 // floppy case
1626 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
1627 {
1628 /// @todo do some more testing, maybe a nice IOCTL!
1629 retValue = true;
1630 }
1631 }
1632 }
1633 return retValue;
1634}
1635#endif // __LINUX__
1636
1637/**
1638 * Runs through all global filters to determine the state of the given
1639 * USB device, then unless ignored, runs trhough filters of all running machines
1640 * (excluding the given one) to automatically capture the device when there is a
1641 * match (the state of the device will be set to USBDeviceCaptured if so, and
1642 * the machine's process will be informed about the auto-capture).
1643 *
1644 * @param aDevice USB device to set state for
1645 * @param aMachine the machine whose filters are to be excluded (can be NULL)
1646 *
1647 * @note the method must be called from under this object's lock
1648 */
1649HRESULT Host::applyAllUSBFilters (ComObjPtr <HostUSBDevice> &aDevice,
1650 SessionMachine *aMachine /* = NULL */)
1651{
1652 LogFlowMember (("Host::applyAllUSBFilters: \n"));
1653
1654 /* ignore unsupported devices */
1655 if (aDevice->state() == USBDeviceState_USBDeviceNotSupported)
1656 return S_OK;
1657 /* ignore unavailable devices as well */
1658 if (aDevice->state() == USBDeviceState_USBDeviceUnavailable)
1659 return S_OK;
1660
1661 VirtualBox::SessionMachineVector machines;
1662 mParent->getOpenedMachines (machines);
1663
1664 /* apply global filters */
1665 USBDeviceFilterList::const_iterator it = mUSBDeviceFilters.begin();
1666 while (it != mUSBDeviceFilters.end())
1667 {
1668 AutoLock filterLock (*it);
1669 const HostUSBDeviceFilter::Data &data = (*it)->data();
1670 if (aDevice->isMatch (data))
1671 {
1672 if (data.mAction == USBDeviceFilterAction_USBDeviceFilterIgnore)
1673 return S_OK;
1674 if (data.mAction == USBDeviceFilterAction_USBDeviceFilterHold)
1675 break;
1676 }
1677 ++ it;
1678 }
1679
1680 /* apply machine filters */
1681 for (size_t i = 0; i < machines.size(); i++)
1682 {
1683 if (aMachine && machines [i] == aMachine)
1684 continue;
1685
1686 applyMachineUSBFilters (machines [i], aDevice);
1687
1688 if (aDevice->state() == USBDeviceState_USBDeviceCaptured)
1689 {
1690 // inform the machine's process about the auto-capture
1691 ComPtr <IUSBDevice> d;
1692 aDevice.queryInterfaceTo (d.asOutParam());
1693 HRESULT rc = machines [i]->onUSBDeviceAttach (d);
1694 if (SUCCEEDED(rc))
1695 return rc;
1696
1697 // the machine rejected it, continue applying filters.
1698 aDevice->reset();
1699 }
1700 }
1701
1702 /* no machine filters were matched.
1703 * if no global filters were matched as well, release the device
1704 * to make it available on the host */
1705 if ( it == mUSBDeviceFilters.end()
1706 && aDevice->state() == USBDeviceState_USBDeviceHeld)
1707 aDevice->setHostDriven();
1708/** @todo dmik, what about USBDeviceFilterHold??? */
1709/**
1710 * bird, everything's ok from what I see. if USBDeviceFilterHold filter was
1711 * matched, setHostDevice() will not (and should not) be called
1712 * (because it != mUSBDeviceFilters.end() in that case).
1713 */
1714
1715 return S_OK;
1716}
1717
1718/**
1719 * Runs through filters of the given machine in order to automatically capture
1720 * the given USB device when there is a match (the state of the device will
1721 * be set to USBDeviceCaptured if so, but the machine's process will *NOT* be)
1722 * informed about the auto-capture).
1723 *
1724 * @param aMachine the machine whose filters are to be run
1725 * @param aDevice USB device, a candidate for auto-attaching
1726 *
1727 * @note Locks aMachine for reading.
1728 */
1729void Host::applyMachineUSBFilters (SessionMachine *aMachine,
1730 ComObjPtr <HostUSBDevice> &aDevice)
1731{
1732 LogFlowThisFunc (("\n"));
1733
1734 AssertReturn (aMachine, (void) 0);
1735 AssertReturn (aDevice->state() != USBDeviceState_USBDeviceUnavailable, (void) 0);
1736
1737 /* We're going to use aMachine which is not our child/parent, add a caller */
1738 AutoCaller autoCaller (aMachine);
1739 if (!autoCaller.isOk())
1740 {
1741 /* silently return, the machine might be not running any more */
1742 return;
1743 }
1744
1745 /* enter the machine's lock because we want to access its USB controller */
1746 AutoReaderLock machineLock (aMachine);
1747
1748 if (aMachine->usbController()->hasMatchingFilter (aDevice))
1749 {
1750 /* try capture the device */
1751 bool ok = aDevice->setCaptured (aMachine);
1752
1753 /*
1754 * false is valid only when the state remains USBDeviceBusy meaning that
1755 * the device is currently busy (being accessed by the host)
1756 */
1757 Assert (ok || aDevice->state() == USBDeviceState_USBDeviceBusy);
1758 NOREF (ok);
1759 }
1760}
1761
1762/**
1763 * Called by USB proxy service when a new device is physically attached
1764 * to the host.
1765 *
1766 * @param aDevice Pointer to the device which has been attached.
1767 */
1768void Host::onUSBDeviceAttached (HostUSBDevice *aDevice)
1769{
1770 LogFlowMember (("Host::onUSBDeviceAttached: aDevice=%p\n", aDevice));
1771 /// @todo (dmik) check locks
1772 AutoLock alock (this);
1773
1774 // add to the collecion
1775 mUSBDevices.push_back (aDevice);
1776
1777 // apply all filters (no need to lock the device, nobody can access it yet)
1778 ComObjPtr <HostUSBDevice> DevPtr(aDevice);
1779 HRESULT rc = applyAllUSBFilters (DevPtr);
1780 AssertComRC (rc);
1781}
1782
1783/**
1784 * Called by USB proxy service (?) when the device is physically detached
1785 * from the host.
1786 *
1787 * @param aDevice Pointer to the device which has been detached.
1788 */
1789void Host::onUSBDeviceDetached (HostUSBDevice *aDevice)
1790{
1791 LogFlowMember (("Host::onUSBDeviceDetached: aDevice=%p\n", aDevice));
1792 /// @todo (dmik) check locks
1793 AutoLock alock (this);
1794
1795 Guid id = aDevice->id();
1796
1797 ComObjPtr <HostUSBDevice> device;
1798 Host::USBDeviceList::iterator it = mUSBDevices.begin();
1799 while (it != mUSBDevices.end())
1800 {
1801 if ((*it)->id() == id)
1802 {
1803 device = (*it);
1804 break;
1805 }
1806 ++ it;
1807 }
1808
1809 AssertReturn (!!device, (void) 0);
1810
1811 // remove from the collecion
1812 mUSBDevices.erase (it);
1813
1814 if (device->machine())
1815 {
1816 // the device is captured by a machine, instruct it to release
1817 alock.unlock();
1818 HRESULT rc = device->machine()->onUSBDeviceDetach (device->id());
1819 AssertComRC (rc);
1820 }
1821}
1822
1823/**
1824 * Called by USB proxy service when the state of the host-driven device
1825 * has changed because of non proxy interaction.
1826 *
1827 * @param aDevice The device in question.
1828 */
1829void Host::onUSBDeviceStateChanged (HostUSBDevice *aDevice)
1830{
1831 LogFlowMember (("Host::onUSBDeviceStateChanged: \n"));
1832 /// @todo (dmik) check locks
1833 AutoLock alock (this);
1834
1835 /** @todo dmik, is there anything we should do here? For instance if the device now is available? */
1836}
1837
1838/**
1839 * Checks for the presense and status of the USB Proxy Service.
1840 * Returns S_OK when the Proxy is present and OK, or E_FAIL and a
1841 * corresponding error message otherwise. Intended to be used by methods
1842 * that rely on the Proxy Service availability.
1843 *
1844 * @note Locks this object for reading.
1845 */
1846HRESULT Host::checkUSBProxyService()
1847{
1848#ifdef VBOX_WITH_USB
1849 AutoLock lock (this);
1850 CHECK_READY();
1851
1852 AssertReturn (mUSBProxyService, E_FAIL);
1853 if (!mUSBProxyService->isActive())
1854 {
1855 /* disable the USB controller completely to avoid assertions if the
1856 * USB proxy service could not start. */
1857
1858 Assert (VBOX_FAILURE (mUSBProxyService->getLastError()));
1859 if (mUSBProxyService->getLastError() == VERR_FILE_NOT_FOUND)
1860 return setError (E_FAIL,
1861 tr ("Could not load the Host USB Proxy Service (%Vrc)."
1862 "The service might be not installed on the host computer"),
1863 mUSBProxyService->getLastError());
1864 else
1865 return setError (E_FAIL,
1866 tr ("Could not load the Host USB Proxy service (%Vrc)"),
1867 mUSBProxyService->getLastError());
1868 }
1869
1870 return S_OK;
1871#else
1872 return E_NOTIMPL;
1873#endif
1874}
1875
1876#ifdef __WIN__
1877
1878/* The original source of the VBoxTAP adapter creation/destruction code has the following copyright */
1879/*
1880 Copyright 2004 by the Massachusetts Institute of Technology
1881
1882 All rights reserved.
1883
1884 Permission to use, copy, modify, and distribute this software and its
1885 documentation for any purpose and without fee is hereby granted,
1886 provided that the above copyright notice appear in all copies and that
1887 both that copyright notice and this permission notice appear in
1888 supporting documentation, and that the name of the Massachusetts
1889 Institute of Technology (M.I.T.) not be used in advertising or publicity
1890 pertaining to distribution of the software without specific, written
1891 prior permission.
1892
1893 M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1894 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1895 M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1896 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1897 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1898 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
1899 SOFTWARE.
1900*/
1901
1902
1903#define NETSHELL_LIBRARY _T("netshell.dll")
1904
1905/**
1906 * Use the IShellFolder API to rename the connection.
1907 */
1908static HRESULT rename_shellfolder (PCWSTR wGuid, PCWSTR wNewName)
1909{
1910 /* This is the GUID for the network connections folder. It is constant.
1911 * {7007ACC7-3202-11D1-AAD2-00805FC1270E} */
1912 const GUID CLSID_NetworkConnections = {
1913 0x7007ACC7, 0x3202, 0x11D1, {
1914 0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E
1915 }
1916 };
1917
1918 LPITEMIDLIST pidl = NULL;
1919 IShellFolder *pShellFolder = NULL;
1920 HRESULT hr;
1921
1922 /* Build the display name in the form "::{GUID}". */
1923 if (wcslen (wGuid) >= MAX_PATH)
1924 return E_INVALIDARG;
1925 WCHAR szAdapterGuid[MAX_PATH + 2] = {0};
1926 swprintf (szAdapterGuid, L"::%ls", wGuid);
1927
1928 /* Create an instance of the network connections folder. */
1929 hr = CoCreateInstance (CLSID_NetworkConnections, NULL,
1930 CLSCTX_INPROC_SERVER, IID_IShellFolder,
1931 reinterpret_cast <LPVOID *> (&pShellFolder));
1932 /* Parse the display name. */
1933 if (SUCCEEDED (hr))
1934 {
1935 hr = pShellFolder->ParseDisplayName (NULL, NULL, szAdapterGuid, NULL,
1936 &pidl, NULL);
1937 }
1938 if (SUCCEEDED (hr))
1939 {
1940 hr = pShellFolder->SetNameOf (NULL, pidl, wNewName, SHGDN_NORMAL,
1941 &pidl);
1942 }
1943
1944 CoTaskMemFree (pidl);
1945
1946 if (pShellFolder)
1947 pShellFolder->Release();
1948
1949 return hr;
1950}
1951
1952extern "C" HRESULT RenameConnection (PCWSTR GuidString, PCWSTR NewName)
1953{
1954 typedef HRESULT (WINAPI *lpHrRenameConnection) (const GUID *, PCWSTR);
1955 lpHrRenameConnection RenameConnectionFunc = NULL;
1956 HRESULT status;
1957
1958 /* First try the IShellFolder interface, which was unimplemented
1959 * for the network connections folder before XP. */
1960 status = rename_shellfolder (GuidString, NewName);
1961 if (status == E_NOTIMPL)
1962 {
1963/** @todo that code doesn't seem to work! */
1964 /* The IShellFolder interface is not implemented on this platform.
1965 * Try the (undocumented) HrRenameConnection API in the netshell
1966 * library. */
1967 CLSID clsid;
1968 HINSTANCE hNetShell;
1969 status = CLSIDFromString ((LPOLESTR) GuidString, &clsid);
1970 if (FAILED(status))
1971 return E_FAIL;
1972 hNetShell = LoadLibrary (NETSHELL_LIBRARY);
1973 if (hNetShell == NULL)
1974 return E_FAIL;
1975 RenameConnectionFunc =
1976 (lpHrRenameConnection) GetProcAddress (hNetShell,
1977 "HrRenameConnection");
1978 if (RenameConnectionFunc == NULL)
1979 {
1980 FreeLibrary (hNetShell);
1981 return E_FAIL;
1982 }
1983 status = RenameConnectionFunc (&clsid, NewName);
1984 FreeLibrary (hNetShell);
1985 }
1986 if (FAILED (status))
1987 return status;
1988
1989 return S_OK;
1990}
1991
1992#define DRIVERHWID _T("vboxtap")
1993
1994#define SetErrBreak(strAndArgs) \
1995 if (1) { \
1996 aErrMsg = Utf8StrFmt strAndArgs; vrc = VERR_GENERAL_FAILURE; break; \
1997 } else do {} while (0)
1998
1999/* static */
2000int Host::createNetworkInterface (SVCHlpClient *aClient,
2001 const Utf8Str &aName,
2002 Guid &aGUID, Utf8Str &aErrMsg)
2003{
2004 LogFlowFuncEnter();
2005 LogFlowFunc (("Network connection name = '%s'\n", aName.raw()));
2006
2007 AssertReturn (aClient, VERR_INVALID_POINTER);
2008 AssertReturn (!aName.isNull(), VERR_INVALID_PARAMETER);
2009
2010 int vrc = VINF_SUCCESS;
2011
2012 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
2013 SP_DEVINFO_DATA DeviceInfoData;
2014 DWORD ret = 0;
2015 BOOL found = FALSE;
2016 BOOL registered = FALSE;
2017 BOOL destroyList = FALSE;
2018 TCHAR pCfgGuidString [50];
2019
2020 do
2021 {
2022 BOOL ok;
2023 GUID netGuid;
2024 SP_DRVINFO_DATA DriverInfoData;
2025 SP_DEVINSTALL_PARAMS DeviceInstallParams;
2026 TCHAR className [MAX_PATH];
2027 DWORD index = 0;
2028 PSP_DRVINFO_DETAIL_DATA pDriverInfoDetail;
2029 /* for our purposes, 2k buffer is more
2030 * than enough to obtain the hardware ID
2031 * of the VBoxTAP driver. */
2032 DWORD detailBuf [2048];
2033
2034 HKEY hkey = NULL;
2035 DWORD cbSize;
2036 DWORD dwValueType;
2037
2038 /* initialize the structure size */
2039 DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
2040 DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
2041
2042 /* copy the net class GUID */
2043 memcpy(&netGuid, &GUID_DEVCLASS_NET, sizeof(GUID_DEVCLASS_NET));
2044
2045 /* create an empty device info set associated with the net class GUID */
2046 hDeviceInfo = SetupDiCreateDeviceInfoList (&netGuid, NULL);
2047 if (hDeviceInfo == INVALID_HANDLE_VALUE)
2048 SetErrBreak (("SetupDiCreateDeviceInfoList failed (0x%08X)",
2049 GetLastError()));
2050
2051 /* get the class name from GUID */
2052 ok = SetupDiClassNameFromGuid (&netGuid, className, MAX_PATH, NULL);
2053 if (!ok)
2054 SetErrBreak (("SetupDiClassNameFromGuid failed (0x%08X)",
2055 GetLastError()));
2056
2057 /* create a device info element and add the new device instance
2058 * key to registry */
2059 ok = SetupDiCreateDeviceInfo (hDeviceInfo, className, &netGuid, NULL, NULL,
2060 DICD_GENERATE_ID, &DeviceInfoData);
2061 if (!ok)
2062 SetErrBreak (("SetupDiCreateDeviceInfo failed (0x%08X)",
2063 GetLastError()));
2064
2065 /* select the newly created device info to be the currently
2066 selected member */
2067 ok = SetupDiSetSelectedDevice (hDeviceInfo, &DeviceInfoData);
2068 if (!ok)
2069 SetErrBreak (("SetupDiSetSelectedDevice failed (0x%08X)",
2070 GetLastError()));
2071
2072 /* build a list of class drivers */
2073 ok = SetupDiBuildDriverInfoList (hDeviceInfo, &DeviceInfoData,
2074 SPDIT_CLASSDRIVER);
2075 if (!ok)
2076 SetErrBreak (("SetupDiBuildDriverInfoList failed (0x%08X)",
2077 GetLastError()));
2078
2079 destroyList = TRUE;
2080
2081 /* enumerate the driver info list */
2082 while (TRUE)
2083 {
2084 BOOL ret;
2085
2086 ret = SetupDiEnumDriverInfo (hDeviceInfo, &DeviceInfoData,
2087 SPDIT_CLASSDRIVER, index, &DriverInfoData);
2088
2089 /* if the function failed and GetLastError() returned
2090 * ERROR_NO_MORE_ITEMS, then we have reached the end of the
2091 * list. Othewise there was something wrong with this
2092 * particular driver. */
2093 if (!ret)
2094 {
2095 if(GetLastError() == ERROR_NO_MORE_ITEMS)
2096 break;
2097 else
2098 {
2099 index++;
2100 continue;
2101 }
2102 }
2103
2104 pDriverInfoDetail = (PSP_DRVINFO_DETAIL_DATA) detailBuf;
2105 pDriverInfoDetail->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
2106
2107 /* if we successfully find the hardware ID and it turns out to
2108 * be the one for the loopback driver, then we are done. */
2109 if (SetupDiGetDriverInfoDetail (hDeviceInfo,
2110 &DeviceInfoData,
2111 &DriverInfoData,
2112 pDriverInfoDetail,
2113 sizeof (detailBuf),
2114 NULL))
2115 {
2116 TCHAR * t;
2117
2118 /* pDriverInfoDetail->HardwareID is a MULTISZ string. Go through the
2119 * whole list and see if there is a match somewhere. */
2120 t = pDriverInfoDetail->HardwareID;
2121 while (t && *t && t < (TCHAR *) &detailBuf [sizeof(detailBuf) / sizeof (detailBuf[0])])
2122 {
2123 if (!_tcsicmp(t, DRIVERHWID))
2124 break;
2125
2126 t += _tcslen(t) + 1;
2127 }
2128
2129 if (t && *t && t < (TCHAR *) &detailBuf [sizeof(detailBuf) / sizeof (detailBuf[0])])
2130 {
2131 found = TRUE;
2132 break;
2133 }
2134 }
2135
2136 index ++;
2137 }
2138
2139 if (!found)
2140 SetErrBreak ((tr ("Could not find Host Interface Networking driver! "
2141 "Please reinstall")));
2142
2143 /* set the loopback driver to be the currently selected */
2144 ok = SetupDiSetSelectedDriver (hDeviceInfo, &DeviceInfoData,
2145 &DriverInfoData);
2146 if (!ok)
2147 SetErrBreak (("SetupDiSetSelectedDriver failed (0x%08X)",
2148 GetLastError()));
2149
2150 /* register the phantom device to prepare for install */
2151 ok = SetupDiCallClassInstaller (DIF_REGISTERDEVICE, hDeviceInfo,
2152 &DeviceInfoData);
2153 if (!ok)
2154 SetErrBreak (("SetupDiCallClassInstaller failed (0x%08X)",
2155 GetLastError()));
2156
2157 /* registered, but remove if errors occur in the following code */
2158 registered = TRUE;
2159
2160 /* ask the installer if we can install the device */
2161 ok = SetupDiCallClassInstaller (DIF_ALLOW_INSTALL, hDeviceInfo,
2162 &DeviceInfoData);
2163 if (!ok)
2164 {
2165 if (GetLastError() != ERROR_DI_DO_DEFAULT)
2166 SetErrBreak (("SetupDiCallClassInstaller (DIF_ALLOW_INSTALL) failed (0x%08X)",
2167 GetLastError()));
2168 /* that's fine */
2169 }
2170
2171 /* install the files first */
2172 ok = SetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES, hDeviceInfo,
2173 &DeviceInfoData);
2174 if (!ok)
2175 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES) failed (0x%08X)",
2176 GetLastError()));
2177
2178 /* get the device install parameters and disable filecopy */
2179 DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
2180 ok = SetupDiGetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
2181 &DeviceInstallParams);
2182 if (ok)
2183 {
2184 DeviceInstallParams.Flags |= DI_NOFILECOPY;
2185 ok = SetupDiSetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
2186 &DeviceInstallParams);
2187 if (!ok)
2188 SetErrBreak (("SetupDiSetDeviceInstallParams failed (0x%08X)",
2189 GetLastError()));
2190 }
2191
2192 /*
2193 * Register any device-specific co-installers for this device,
2194 */
2195
2196 ok = SetupDiCallClassInstaller (DIF_REGISTER_COINSTALLERS,
2197 hDeviceInfo,
2198 &DeviceInfoData);
2199 if (!ok)
2200 SetErrBreak (("SetupDiCallClassInstaller (DIF_REGISTER_COINSTALLERS) failed (0x%08X)",
2201 GetLastError()));
2202
2203 /*
2204 * install any installer-specified interfaces.
2205 * and then do the real install
2206 */
2207 ok = SetupDiCallClassInstaller (DIF_INSTALLINTERFACES,
2208 hDeviceInfo,
2209 &DeviceInfoData);
2210 if (!ok)
2211 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLINTERFACES) failed (0x%08X)",
2212 GetLastError()));
2213
2214 ok = SetupDiCallClassInstaller (DIF_INSTALLDEVICE,
2215 hDeviceInfo,
2216 &DeviceInfoData);
2217 if (!ok)
2218 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLDEVICE) failed (0x%08X)",
2219 GetLastError()));
2220
2221 /* Figure out NetCfgInstanceId */
2222 hkey = SetupDiOpenDevRegKey (hDeviceInfo,
2223 &DeviceInfoData,
2224 DICS_FLAG_GLOBAL,
2225 0,
2226 DIREG_DRV,
2227 KEY_READ);
2228 if (hkey == INVALID_HANDLE_VALUE)
2229 SetErrBreak (("SetupDiOpenDevRegKey failed (0x%08X)",
2230 GetLastError()));
2231
2232 cbSize = sizeof (pCfgGuidString);
2233 DWORD ret;
2234 ret = RegQueryValueEx (hkey, _T ("NetCfgInstanceId"), NULL,
2235 &dwValueType, (LPBYTE) pCfgGuidString, &cbSize);
2236 RegCloseKey (hkey);
2237
2238 ret = RenameConnection (pCfgGuidString, Bstr (aName));
2239 if (FAILED (ret))
2240 SetErrBreak (("Failed to set interface name (ret=0x%08X, "
2241 "pCfgGuidString='%ls', cbSize=%d)",
2242 ret, pCfgGuidString, cbSize));
2243 }
2244 while (0);
2245
2246 /*
2247 * cleanup
2248 */
2249
2250 if (hDeviceInfo != INVALID_HANDLE_VALUE)
2251 {
2252 /* an error has occured, but the device is registered, we must remove it */
2253 if (ret != 0 && registered)
2254 SetupDiCallClassInstaller (DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
2255
2256 found = SetupDiDeleteDeviceInfo (hDeviceInfo, &DeviceInfoData);
2257
2258 /* destroy the driver info list */
2259 if (destroyList)
2260 SetupDiDestroyDriverInfoList (hDeviceInfo, &DeviceInfoData,
2261 SPDIT_CLASSDRIVER);
2262 /* clean up the device info set */
2263 SetupDiDestroyDeviceInfoList (hDeviceInfo);
2264 }
2265
2266 /* return the network connection GUID on success */
2267 if (VBOX_SUCCESS (vrc))
2268 {
2269 /* remove the curly bracket at the end */
2270 pCfgGuidString [_tcslen (pCfgGuidString) - 1] = '\0';
2271 LogFlowFunc (("Network connection GUID string = {%ls}\n", pCfgGuidString + 1));
2272
2273 aGUID = Guid (Utf8Str (pCfgGuidString + 1));
2274 LogFlowFunc (("Network connection GUID = {%Vuuid}\n", aGUID.raw()));
2275 Assert (!aGUID.isEmpty());
2276 }
2277
2278 LogFlowFunc (("vrc=%Vrc\n", vrc));
2279 LogFlowFuncLeave();
2280 return vrc;
2281}
2282
2283/* static */
2284int Host::removeNetworkInterface (SVCHlpClient *aClient,
2285 const Guid &aGUID,
2286 Utf8Str &aErrMsg)
2287{
2288 LogFlowFuncEnter();
2289 LogFlowFunc (("Network connection GUID = {%Vuuid}\n", aGUID.raw()));
2290
2291 AssertReturn (aClient, VERR_INVALID_POINTER);
2292 AssertReturn (!aGUID.isEmpty(), VERR_INVALID_PARAMETER);
2293
2294 int vrc = VINF_SUCCESS;
2295
2296 do
2297 {
2298 TCHAR lszPnPInstanceId [512] = {0};
2299
2300 /* We have to find the device instance ID through a registry search */
2301
2302 HKEY hkeyNetwork = 0;
2303 HKEY hkeyConnection = 0;
2304
2305 do
2306 {
2307 char strRegLocation [256];
2308 sprintf (strRegLocation,
2309 "SYSTEM\\CurrentControlSet\\Control\\Network\\"
2310 "{4D36E972-E325-11CE-BFC1-08002BE10318}\\{%s}",
2311 aGUID.toString().raw());
2312 LONG status;
2313 status = RegOpenKeyExA (HKEY_LOCAL_MACHINE, strRegLocation, 0,
2314 KEY_READ, &hkeyNetwork);
2315 if ((status != ERROR_SUCCESS) || !hkeyNetwork)
2316 SetErrBreak ((
2317 tr ("Host interface network is not found in registry (%s) [1]"),
2318 strRegLocation));
2319
2320 status = RegOpenKeyExA (hkeyNetwork, "Connection", 0,
2321 KEY_READ, &hkeyConnection);
2322 if ((status != ERROR_SUCCESS) || !hkeyConnection)
2323 SetErrBreak ((
2324 tr ("Host interface network is not found in registry (%s) [2]"),
2325 strRegLocation));
2326
2327 DWORD len = sizeof (lszPnPInstanceId);
2328 DWORD dwKeyType;
2329 status = RegQueryValueExW (hkeyConnection, L"PnPInstanceID", NULL,
2330 &dwKeyType, (LPBYTE) lszPnPInstanceId, &len);
2331 if ((status != ERROR_SUCCESS) || (dwKeyType != REG_SZ))
2332 SetErrBreak ((
2333 tr ("Host interface network is not found in registry (%s) [3]"),
2334 strRegLocation));
2335 }
2336 while (0);
2337
2338 if (hkeyConnection)
2339 RegCloseKey (hkeyConnection);
2340 if (hkeyNetwork)
2341 RegCloseKey (hkeyNetwork);
2342
2343 if (VBOX_FAILURE (vrc))
2344 break;
2345
2346 /*
2347 * Now we are going to enumerate all network devices and
2348 * wait until we encounter the right device instance ID
2349 */
2350
2351 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
2352
2353 do
2354 {
2355 BOOL ok;
2356 DWORD ret = 0;
2357 GUID netGuid;
2358 SP_DEVINFO_DATA DeviceInfoData;
2359 DWORD index = 0;
2360 BOOL found = FALSE;
2361 DWORD size = 0;
2362
2363 /* initialize the structure size */
2364 DeviceInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
2365
2366 /* copy the net class GUID */
2367 memcpy (&netGuid, &GUID_DEVCLASS_NET, sizeof (GUID_DEVCLASS_NET));
2368
2369 /* return a device info set contains all installed devices of the Net class */
2370 hDeviceInfo = SetupDiGetClassDevs (&netGuid, NULL, NULL, DIGCF_PRESENT);
2371
2372 if (hDeviceInfo == INVALID_HANDLE_VALUE)
2373 SetErrBreak (("SetupDiGetClassDevs failed (0x%08X)", GetLastError()));
2374
2375 /* enumerate the driver info list */
2376 while (TRUE)
2377 {
2378 TCHAR *deviceHwid;
2379
2380 ok = SetupDiEnumDeviceInfo (hDeviceInfo, index, &DeviceInfoData);
2381
2382 if (!ok)
2383 {
2384 if (GetLastError() == ERROR_NO_MORE_ITEMS)
2385 break;
2386 else
2387 {
2388 index++;
2389 continue;
2390 }
2391 }
2392
2393 /* try to get the hardware ID registry property */
2394 ok = SetupDiGetDeviceRegistryProperty (hDeviceInfo,
2395 &DeviceInfoData,
2396 SPDRP_HARDWAREID,
2397 NULL,
2398 NULL,
2399 0,
2400 &size);
2401 if (!ok)
2402 {
2403 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
2404 {
2405 index++;
2406 continue;
2407 }
2408
2409 deviceHwid = (TCHAR *) malloc (size);
2410 ok = SetupDiGetDeviceRegistryProperty (hDeviceInfo,
2411 &DeviceInfoData,
2412 SPDRP_HARDWAREID,
2413 NULL,
2414 (PBYTE)deviceHwid,
2415 size,
2416 NULL);
2417 if (!ok)
2418 {
2419 free (deviceHwid);
2420 deviceHwid = NULL;
2421 index++;
2422 continue;
2423 }
2424 }
2425 else
2426 {
2427 /* something is wrong. This shouldn't have worked with a NULL buffer */
2428 index++;
2429 continue;
2430 }
2431
2432 for (TCHAR *t = deviceHwid;
2433 t && *t && t < &deviceHwid[size / sizeof(TCHAR)];
2434 t += _tcslen (t) + 1)
2435 {
2436 if (!_tcsicmp (DRIVERHWID, t))
2437 {
2438 /* get the device instance ID */
2439 TCHAR devID [MAX_DEVICE_ID_LEN];
2440 if (CM_Get_Device_ID(DeviceInfoData.DevInst,
2441 devID, MAX_DEVICE_ID_LEN, 0) == CR_SUCCESS)
2442 {
2443 /* compare to what we determined before */
2444 if (wcscmp(devID, lszPnPInstanceId) == 0)
2445 {
2446 found = TRUE;
2447 break;
2448 }
2449 }
2450 }
2451 }
2452
2453 if (deviceHwid)
2454 {
2455 free (deviceHwid);
2456 deviceHwid = NULL;
2457 }
2458
2459 if (found)
2460 break;
2461
2462 index++;
2463 }
2464
2465 if (found == FALSE)
2466 SetErrBreak ((tr ("Host Interface Network driver not found (0x%08X)"),
2467 GetLastError()));
2468
2469 ok = SetupDiSetSelectedDevice (hDeviceInfo, &DeviceInfoData);
2470 if (!ok)
2471 SetErrBreak (("SetupDiSetSelectedDevice failed (0x%08X)",
2472 GetLastError()));
2473
2474 ok = SetupDiCallClassInstaller (DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
2475 if (!ok)
2476 SetErrBreak (("SetupDiCallClassInstaller (DIF_REMOVE) failed (0x%08X)",
2477 GetLastError()));
2478 }
2479 while (0);
2480
2481 /* clean up the device info set */
2482 if (hDeviceInfo != INVALID_HANDLE_VALUE)
2483 SetupDiDestroyDeviceInfoList (hDeviceInfo);
2484
2485 if (VBOX_FAILURE (vrc))
2486 break;
2487 }
2488 while (0);
2489
2490 LogFlowFunc (("vrc=%Vrc\n", vrc));
2491 LogFlowFuncLeave();
2492 return vrc;
2493}
2494
2495#undef SetErrBreak
2496
2497/* static */
2498HRESULT Host::networkInterfaceHelperClient (SVCHlpClient *aClient,
2499 Progress *aProgress,
2500 void *aUser, int *aVrc)
2501{
2502 LogFlowFuncEnter();
2503 LogFlowFunc (("aClient={%p}, aProgress={%p}, aUser={%p}\n",
2504 aClient, aProgress, aUser));
2505
2506 AssertReturn ((aClient == NULL && aProgress == NULL && aVrc == NULL) ||
2507 (aClient != NULL && aProgress != NULL && aVrc != NULL),
2508 E_POINTER);
2509 AssertReturn (aUser, E_POINTER);
2510
2511 std::auto_ptr <NetworkInterfaceHelperClientData>
2512 d (static_cast <NetworkInterfaceHelperClientData *> (aUser));
2513
2514 if (aClient == NULL)
2515 {
2516 /* "cleanup only" mode, just return (it will free aUser) */
2517 return S_OK;
2518 }
2519
2520 HRESULT rc = S_OK;
2521 int vrc = VINF_SUCCESS;
2522
2523 switch (d->msgCode)
2524 {
2525 case SVCHlpMsg::CreateHostNetworkInterface:
2526 {
2527 LogFlowFunc (("CreateHostNetworkInterface:\n"));
2528 LogFlowFunc (("Network connection name = '%ls'\n", d->name.raw()));
2529
2530 /* write message and parameters */
2531 vrc = aClient->write (d->msgCode);
2532 if (VBOX_FAILURE (vrc)) break;
2533 vrc = aClient->write (Utf8Str (d->name));
2534 if (VBOX_FAILURE (vrc)) break;
2535
2536 /* wait for a reply */
2537 bool endLoop = false;
2538 while (!endLoop)
2539 {
2540 SVCHlpMsg::Code reply = SVCHlpMsg::Null;
2541
2542 vrc = aClient->read (reply);
2543 if (VBOX_FAILURE (vrc)) break;
2544
2545 switch (reply)
2546 {
2547 case SVCHlpMsg::CreateHostNetworkInterface_OK:
2548 {
2549 /* read the GUID */
2550 Guid guid;
2551 vrc = aClient->read (guid);
2552 if (VBOX_FAILURE (vrc)) break;
2553
2554 LogFlowFunc (("Network connection GUID = {%Vuuid}\n", guid.raw()));
2555
2556 /* initialize the object returned to the caller by
2557 * CreateHostNetworkInterface() */
2558 rc = d->iface->init (d->name, guid);
2559 endLoop = true;
2560 break;
2561 }
2562 case SVCHlpMsg::Error:
2563 {
2564 /* read the error message */
2565 Utf8Str errMsg;
2566 vrc = aClient->read (errMsg);
2567 if (VBOX_FAILURE (vrc)) break;
2568
2569 rc = setError (E_FAIL, errMsg);
2570 endLoop = true;
2571 break;
2572 }
2573 default:
2574 {
2575 endLoop = true;
2576 ComAssertMsgFailedBreak ((
2577 "Invalid message code %d (%08lX)\n",
2578 reply, reply),
2579 rc = E_FAIL);
2580 }
2581 }
2582 }
2583
2584 break;
2585 }
2586 case SVCHlpMsg::RemoveHostNetworkInterface:
2587 {
2588 LogFlowFunc (("RemoveHostNetworkInterface:\n"));
2589 LogFlowFunc (("Network connection GUID = {%Vuuid}\n", d->guid.raw()));
2590
2591 /* write message and parameters */
2592 vrc = aClient->write (d->msgCode);
2593 if (VBOX_FAILURE (vrc)) break;
2594 vrc = aClient->write (d->guid);
2595 if (VBOX_FAILURE (vrc)) break;
2596
2597 /* wait for a reply */
2598 bool endLoop = false;
2599 while (!endLoop)
2600 {
2601 SVCHlpMsg::Code reply = SVCHlpMsg::Null;
2602
2603 vrc = aClient->read (reply);
2604 if (VBOX_FAILURE (vrc)) break;
2605
2606 switch (reply)
2607 {
2608 case SVCHlpMsg::OK:
2609 {
2610 /* no parameters */
2611 rc = S_OK;
2612 endLoop = true;
2613 break;
2614 }
2615 case SVCHlpMsg::Error:
2616 {
2617 /* read the error message */
2618 Utf8Str errMsg;
2619 vrc = aClient->read (errMsg);
2620 if (VBOX_FAILURE (vrc)) break;
2621
2622 rc = setError (E_FAIL, errMsg);
2623 endLoop = true;
2624 break;
2625 }
2626 default:
2627 {
2628 endLoop = true;
2629 ComAssertMsgFailedBreak ((
2630 "Invalid message code %d (%08lX)\n",
2631 reply, reply),
2632 rc = E_FAIL);
2633 }
2634 }
2635 }
2636
2637 break;
2638 }
2639 default:
2640 ComAssertMsgFailedBreak ((
2641 "Invalid message code %d (%08lX)\n",
2642 d->msgCode, d->msgCode),
2643 rc = E_FAIL);
2644 }
2645
2646 if (aVrc)
2647 *aVrc = vrc;
2648
2649 LogFlowFunc (("rc=0x%08X, vrc=%Vrc\n", rc, vrc));
2650 LogFlowFuncLeave();
2651 return rc;
2652}
2653
2654/* static */
2655int Host::networkInterfaceHelperServer (SVCHlpClient *aClient,
2656 SVCHlpMsg::Code aMsgCode)
2657{
2658 LogFlowFuncEnter();
2659 LogFlowFunc (("aClient={%p}, aMsgCode=%d\n", aClient, aMsgCode));
2660
2661 AssertReturn (aClient, VERR_INVALID_POINTER);
2662
2663 int vrc = VINF_SUCCESS;
2664
2665 switch (aMsgCode)
2666 {
2667 case SVCHlpMsg::CreateHostNetworkInterface:
2668 {
2669 LogFlowFunc (("CreateHostNetworkInterface:\n"));
2670
2671 Utf8Str name;
2672 vrc = aClient->read (name);
2673 if (VBOX_FAILURE (vrc)) break;
2674
2675 Guid guid;
2676 Utf8Str errMsg;
2677 vrc = createNetworkInterface (aClient, name, guid, errMsg);
2678
2679 if (VBOX_SUCCESS (vrc))
2680 {
2681 /* write success followed by GUID */
2682 vrc = aClient->write (SVCHlpMsg::CreateHostNetworkInterface_OK);
2683 if (VBOX_FAILURE (vrc)) break;
2684 vrc = aClient->write (guid);
2685 if (VBOX_FAILURE (vrc)) break;
2686 }
2687 else
2688 {
2689 /* write failure followed by error message */
2690 if (errMsg.isEmpty())
2691 errMsg = Utf8StrFmt ("Unspecified error (%Vrc)", vrc);
2692 vrc = aClient->write (SVCHlpMsg::Error);
2693 if (VBOX_FAILURE (vrc)) break;
2694 vrc = aClient->write (errMsg);
2695 if (VBOX_FAILURE (vrc)) break;
2696 }
2697
2698 break;
2699 }
2700 case SVCHlpMsg::RemoveHostNetworkInterface:
2701 {
2702 LogFlowFunc (("RemoveHostNetworkInterface:\n"));
2703
2704 Guid guid;
2705 vrc = aClient->read (guid);
2706 if (VBOX_FAILURE (vrc)) break;
2707
2708 Utf8Str errMsg;
2709 vrc = removeNetworkInterface (aClient, guid, errMsg);
2710
2711 if (VBOX_SUCCESS (vrc))
2712 {
2713 /* write parameter-less success */
2714 vrc = aClient->write (SVCHlpMsg::OK);
2715 if (VBOX_FAILURE (vrc)) break;
2716 }
2717 else
2718 {
2719 /* write failure followed by error message */
2720 if (errMsg.isEmpty())
2721 errMsg = Utf8StrFmt ("Unspecified error (%Vrc)", vrc);
2722 vrc = aClient->write (SVCHlpMsg::Error);
2723 if (VBOX_FAILURE (vrc)) break;
2724 vrc = aClient->write (errMsg);
2725 if (VBOX_FAILURE (vrc)) break;
2726 }
2727
2728 break;
2729 }
2730 default:
2731 AssertMsgFailedBreak ((
2732 "Invalid message code %d (%08lX)\n", aMsgCode, aMsgCode),
2733 VERR_GENERAL_FAILURE);
2734 }
2735
2736 LogFlowFunc (("vrc=%Vrc\n", vrc));
2737 LogFlowFuncLeave();
2738 return vrc;
2739}
2740
2741#endif /* __WIN__ */
2742
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