VirtualBox

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

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

Main/Frontends: Next step to support asynchronous USB device flow.

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