VirtualBox

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

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

InnoTek -> innotek: all the headers and comments.

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