VirtualBox

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

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

Main: Preparations for async USB handling.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette